diff --git a/src/seismometer/configuration/__init__.py b/src/seismometer/configuration/__init__.py index 83d8a84..669b1b2 100644 --- a/src/seismometer/configuration/__init__.py +++ b/src/seismometer/configuration/__init__.py @@ -1,3 +1,2 @@ from .config import ConfigProvider from .model import AggregationStrategies, MergeStrategies -from .options import Option, TemplateOptions, template_options diff --git a/src/seismometer/configuration/config.py b/src/seismometer/configuration/config.py index 1215d69..515a730 100644 --- a/src/seismometer/configuration/config.py +++ b/src/seismometer/configuration/config.py @@ -5,7 +5,6 @@ from seismometer.core.io import load_yaml from .model import DataUsage, Event, EventDictionary, OtherInfo, PredictionDictionary -from .options import Option, template_options class ConfigProvider: @@ -32,7 +31,7 @@ class ConfigProvider: data_dir : Optional[str | Path], optional Specifies the path to the data directory, by default None; it uses data_dir from the primary config file, which is where data dictionaries are written/read. - template_notebook : Optional[Option], optional + template_notebook : Optional[object], optional Unused. definitions : Optional[dict], optional A dictionary of definitions to use instead of loading those specified by configuration, by default None. @@ -48,7 +47,7 @@ def __init__( usage_config: str | Path = None, info_dir: str | Path = None, data_dir: str | Path = None, - template_notebook: Option = None, + template_notebook: object = None, definitions: dict = None, output_path: str | Path = None, ): @@ -118,17 +117,9 @@ def config(self, config_def: OtherInfo): self._template = None @property - def template(self) -> Option: + def template(self) -> None: """The template used for building a model-specific seismograph notebook.""" - if self._template is None: - template_name = self.config.template - if template_name not in template_options: - raise ValueError( - f"Template option {template_name} not found in known options: {', '.join(template_options)}" - ) - self._template = template_options[template_name] - - return self._template + raise NotImplementedError("Template building is not implemented") @property def info_dir(self) -> Path: @@ -385,11 +376,7 @@ def set_output(self, output: Path, nb_prefix: str = ""): output = output.resolve() if not output.suffix: # no suffix implies directory self._output_dir = output - filename = self.template.value - if filename: - self._output_notebook = nb_prefix + filename.name else: # file specified - self._output_notebook = output.name if str(output.parent) == ".": # No path given, use config self._output_dir = self.info_dir or output.parent else: diff --git a/src/seismometer/configuration/options.py b/src/seismometer/configuration/options.py deleted file mode 100644 index 87b7eca..0000000 --- a/src/seismometer/configuration/options.py +++ /dev/null @@ -1,77 +0,0 @@ -from collections import namedtuple -from importlib.resources import files as _files -from pathlib import Path - -Pathlike = str | Path -Option = namedtuple("Option", ["name", "value"]) - - -# region Template Selection -class TemplateOptions: - """ - A class to manage the available templates for the builder. - - Acts similar to an Enum, returning Options that have a name and Path value. - Can be accessed like a dictionary. - Cannot override the core templates. - - Returns - ------- - Option - A named tuple with name and path fields. - - Yields - ------ - Iterates over all known templates - Returns names (keys) of the templates. - """ - - _base_templates: dict[str, Path] = { - "binary": "classifier_bin.ipynb", - } - - def __init__(self): - self._custom_templates: dict[str, Path] = {} - - def __getitem__(self, key): - """Access options directly off instance like a dictionary.""" - if key in TemplateOptions._base_templates: - import seismometer.builder.resources - - res = _files(seismometer.builder.resources) / self._base_templates[key] - return Option(key, res) - if key in self._custom_templates: - return Option(key, self._custom_templates[key]) - raise AttributeError(f"Template not found: {key}") - - def __setitem__(self, key, value): - """Set new templates as attributes; cannot override base templates.""" - if key in TemplateOptions._base_templates: - raise ValueError(f"Cannot override base template: {key}") - self._custom_templates[key] = value - - def __iter__(self): - """List all registered templates.""" - yield from TemplateOptions._base_templates.keys() - yield from self._custom_templates.keys() - - def add_adhoc_template(self, filepath: Pathlike) -> Option: - """ - Adds a custom template to those known under "custom". - - Parameters - ---------- - filepath : Pathlike - The location of the template notebook. - - Returns - ------- - Option - The Option tuple for the new template. - """ - self["custom"] = Path(filepath) - return self["custom"] - - -# A global instance of the TemplateOptions -template_options = TemplateOptions() diff --git a/src/seismometer/core/io.py b/src/seismometer/core/io.py index 4cc2d4e..0bf8464 100644 --- a/src/seismometer/core/io.py +++ b/src/seismometer/core/io.py @@ -123,31 +123,20 @@ def resolve_filename( # region load functions -def load_notebook(*, nb_template: "Option" = None, filepath: Optional[Pathlike] = None) -> nbformat.NotebookNode: +def load_notebook(filepath: Pathlike) -> nbformat.NotebookNode: """ Loads a notebook from a file. - Can load a notebook from a template Option or from file; prioritizing the path. - Parameters ---------- - nb_template : Optional[Option], optional - The template to load, by default None. - filepath : Optional[Pathlike], optional + filepath : Pathlike, optional The path to a notebook, by default None. Returns ------- nbformat.NotebookNode The loaded notebook. - """ - if filepath is None: - try: - filepath = nb_template.value - except AttributeError: - raise ValueError("Either a valid nb_template or a filepath for the template notebook must be provided.") - return _load(read_ipynb, filepath) diff --git a/tests/configuration/test_options.py b/tests/configuration/test_options.py deleted file mode 100644 index b3c85c6..0000000 --- a/tests/configuration/test_options.py +++ /dev/null @@ -1,60 +0,0 @@ -from importlib.resources import files as ir_files -from pathlib import Path - -import pytest - -import seismometer.configuration.options as undertest - -mpp = ir_files("seismometer.builder.resources") -TEMPLATE_DIR = Path(next(mpp.iterdir())).parent -RELEASED_TEMPLATES = ["binary"] - - -class TestTemplateOptions: - def test_preconstructed_has_templates(self): - assert list(undertest.template_options) == RELEASED_TEMPLATES - - def test_default_has_templates(self): - assert list(undertest.TemplateOptions()) == ["binary"] - - def test_set_over_released_fails(self): - to = undertest.TemplateOptions() - with pytest.raises(ValueError, match="Cannot*"): - to["binary"] = "custom.ipynb" - - def test_missing_get_raises(self): - to = undertest.TemplateOptions() - with pytest.raises(AttributeError, match="Template not found*"): - _ = to["missing"] - - def test_set_other_is_accessible(self): - to = undertest.TemplateOptions() - to["NEW"] = "custom.ipynb" - assert list(to) == RELEASED_TEMPLATES + ["NEW"] - - def test_add_adhoc_adds_custom(self): - expected = undertest.Option("custom", Path("custom.ipynb")) - to = undertest.TemplateOptions() - - added = to.add_adhoc_template("custom.ipynb") - - assert list(to) == RELEASED_TEMPLATES + ["custom"] - assert added == expected - - @pytest.mark.parametrize("key", RELEASED_TEMPLATES) - def test_can_access_released(self, key): - expected_resource_dir = TEMPLATE_DIR - - to = undertest.TemplateOptions() - - assert to[key].name == key - # Assumes install never separates the file and resources - assert expected_resource_dir in to[key].value.parents - - def test_can_access_added(self): - to = undertest.TemplateOptions() - - to["test"] = "test.ipynb" - assert to["test"].name == "test" - assert to["test"].value == "test.ipynb" - assert to._custom_templates == {"test": "test.ipynb"} diff --git a/tests/configuration/test_provider.py b/tests/configuration/test_provider.py index 0963443..049df12 100644 --- a/tests/configuration/test_provider.py +++ b/tests/configuration/test_provider.py @@ -31,7 +31,6 @@ class TestConfigProvider: ("interventions", {}), ("prediction_columns", ["Age", "Input", "Score", "ScoringTime", "encounter_id", "id"]), ("censor_min_count", 15), - ("output_notebook", "classifier_bin.ipynb"), ], ) def test_testconfig_is_valid_simple_object(self, property, value, res): diff --git a/tests/core/test_io.py b/tests/core/test_io.py index 96cf153..1e9bdba 100644 --- a/tests/core/test_io.py +++ b/tests/core/test_io.py @@ -7,7 +7,6 @@ from conftest import res, tmp_as_current # noqa: F401 import seismometer.core.io as undertest -from seismometer.configuration.options import Option class Test_IO: @@ -46,7 +45,7 @@ def test_slugify_raises(self, string): @pytest.fixture def testdir(res) -> Path: - return res / "builder" + return res / "io" # region Loaders @@ -72,16 +71,6 @@ class TestLoadNotebook: + '"nbformat": 4, "nbformat_minor": 2}' ) - def test_load_notebook_with_invalid_input(self): - with pytest.raises(ValueError): - _ = undertest.load_notebook() - - def test_load_notebook_with_nb_template(self, testdir): - file = testdir / TestLoadNotebook.filepath - nb_template = Option(value=file, name="test") - result = undertest.load_notebook(nb_template=nb_template) - assert result == TestLoadNotebook.expected - def test_load_notebook_with_filepath(self, testdir): filepath = testdir / TestLoadNotebook.filepath result = undertest.load_notebook(filepath=filepath)