diff --git a/CHANGES.rst b/CHANGES.rst index 6f7435cf..e63fda64 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,6 +8,7 @@ - Fix ``datetime.utcnow()`` DeprecationWarning [#134] - Provide ``asn_n_members=1`` when opening the ``Step`` dataset for ``get_crds_parameters`` [#142] +- Fix bug in handling of ``pathlib.Path`` objects as ``Step`` inputs [#143] 0.5.1 (2023-10-02) ================== diff --git a/src/stpipe/log.py b/src/stpipe/log.py index d1819c01..d7e85bff 100644 --- a/src/stpipe/log.py +++ b/src/stpipe/log.py @@ -5,6 +5,7 @@ import io import logging import os +import pathlib import sys import threading from contextlib import contextmanager @@ -176,7 +177,7 @@ def load_configuration(config_file): Parameters ---------- - config_file : str or readable file-like object + config_file : str, pathlib.Path instance or readable file-like object """ def _level_check(value): @@ -192,6 +193,8 @@ def _level_check(value): return value spec = config_parser.load_spec_file(LogConfig) + if isinstance(config_file, pathlib.Path): + config_file = str(config_file) config = ConfigObj(config_file, raise_errors=True, interpolation=False) val = validate.Validator() val.functions["level"] = _level_check diff --git a/src/stpipe/step.py b/src/stpipe/step.py index 4f30bd05..410fa817 100644 --- a/src/stpipe/step.py +++ b/src/stpipe/step.py @@ -18,6 +18,7 @@ split, splitext, ) +from pathlib import Path from typing import ClassVar try: @@ -248,7 +249,7 @@ def from_config_section( If not provided, try the following (in order): - The ``name`` parameter in the config file fragment - The name of returned class - config_file : str, optional + config_file : str or pathlib.Path, optional The path to the config file that created this step, if any. This is used to resolve relative file name parameters in the config file. @@ -323,7 +324,7 @@ def __init__( fully-qualified name for this step, and to determine the mode in which to run this step. - config_file : str path, optional + config_file : str or pathlib.Path, optional The path to the config file that this step was initialized with. Use to determine relative path names of other config files. @@ -907,7 +908,7 @@ def set_primary_input(self, obj, exclusive=True): Parameters ---------- - obj : str or instance of AbstractDataModel + obj : str, pathlib.Path, or instance of AbstractDataModel The object to base the name on. If a datamodel, use Datamodel.meta.filename. @@ -920,8 +921,8 @@ def set_primary_input(self, obj, exclusive=True): err_message = f"Cannot set master input file name from object {obj}" parent_input_filename = self.search_attr("_input_filename") if not exclusive or parent_input_filename is None: - if isinstance(obj, str): - self._input_filename = obj + if isinstance(obj, (str, Path)): + self._input_filename = str(obj) elif isinstance(obj, AbstractDataModel): try: self._input_filename = obj.meta.filename @@ -1298,7 +1299,7 @@ def export_config(self, filename, include_metadata=False): Parameters ---------- - filename : str or pathlib.PurePath + filename : str or pathlib.Path Path to config file. include_metadata : bool, optional @@ -1376,7 +1377,7 @@ def build_config(cls, input, **kwargs): # noqa: A002 if "config_file" in kwargs: config_file = kwargs["config_file"] del kwargs["config_file"] - config_from_file = config_parser.load_config_file(config_file) + config_from_file = config_parser.load_config_file(str(config_file)) config_parser.merge_config(config, config_from_file) config_dir = os.path.dirname(config_file) else: diff --git a/tests/test_logger.py b/tests/test_logger.py index 432224ff..28708f38 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -13,8 +13,8 @@ def _clean_up_logging(): stpipe_log.load_configuration(io.BytesIO(stpipe_log.DEFAULT_CONFIGURATION)) -def test_configuration(tmpdir): - logfilename = tmpdir.join("output.log") +def test_configuration(tmp_path): + logfilename = tmp_path / "output.log" configuration = f""" [.] diff --git a/tests/test_step.py b/tests/test_step.py index 22c80ef7..d4bfe9f3 100644 --- a/tests/test_step.py +++ b/tests/test_step.py @@ -76,9 +76,9 @@ class ListArgStep(Step): @pytest.fixture() -def config_file_pipe(tmpdir): +def config_file_pipe(tmp_path): """Create a config file""" - config_file = str(tmpdir / "simple_pipe.asdf") + config_file = tmp_path / "simple_pipe.asdf" tree = { "class": "test_step.SimplePipe", @@ -104,9 +104,9 @@ def config_file_pipe(tmpdir): @pytest.fixture() -def config_file_step(tmpdir): +def config_file_step(tmp_path): """Create a config file""" - config_file = str(tmpdir / "simple_step.asdf") + config_file = tmp_path / "simple_step.asdf" tree = { "class": "test_step.SimpleStep", @@ -122,9 +122,9 @@ def config_file_step(tmpdir): @pytest.fixture() -def config_file_list_arg_step(tmpdir): +def config_file_list_arg_step(tmp_path): """Create a config file""" - config_file = str(tmpdir / "list_arg_step.asdf") + config_file = tmp_path / "list_arg_step.asdf" tree = { "class": "test_step.ListArgStep", @@ -287,6 +287,10 @@ def test_step_list_args(config_file_list_arg_step): "science.fits", config_file=config_file_list_arg_step ) assert returned_config_file == config_file_list_arg_step + + # Command line tests below need the config file path to be a string + returned_config_file = str(returned_config_file) + c, *_ = cmdline.just_the_step_from_cmdline( [ "filename.fits", @@ -376,10 +380,10 @@ def test_step_list_args(config_file_list_arg_step): ) -def test_logcfg_routing(tmpdir): - cfg = f"""[*]\nlevel = INFO\nhandler = file:{tmpdir}/myrun.log""" +def test_logcfg_routing(tmp_path): + cfg = f"""[*]\nlevel = INFO\nhandler = file:{tmp_path}/myrun.log""" - logcfg_file = str(tmpdir / "stpipe-log.cfg") + logcfg_file = tmp_path / "stpipe-log.cfg" with open(logcfg_file, "w") as f: f.write(cfg) @@ -394,7 +398,7 @@ def test_logcfg_routing(tmpdir): logdict[log].removeHandler(handler) handler.close() - with open(tmpdir / "myrun.log") as f: + with open(tmp_path / "myrun.log") as f: fulltext = "\n".join(list(f)) assert "called out a warning" in fulltext