Skip to content

Commit

Permalink
test hooks without requiring jwst
Browse files Browse the repository at this point in the history
  • Loading branch information
braingram committed Oct 14, 2024
1 parent 4667ada commit 1e50496
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 36 deletions.
9 changes: 9 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,12 @@ def tmp_cwd(tmp_path):
yield tmp_path
finally:
os.chdir(old_dir)


@pytest.fixture()
def disable_crds_steppars(monkeypatch):
"""
Disable crds steppars (by setting the environment variable)
"""
monkeypatch.setitem(os.environ, "STPIPE_DISABLE_CRDS_STEPPARS", "True")
yield
102 changes: 66 additions & 36 deletions tests/test_hooks.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,63 @@
import pytest
import asdf

pytest.importorskip("jwst")
from stpipe.pipeline import Pipeline
from stpipe.step import Step

from jwst.stpipe import Pipeline, Step # noqa: E402

class FakeDataModel:
def __init__(self, data_id=None):
self.data_id = data_id

class ShovelPixelsStep(Step):
@property
def crds_observatory(self):
return "jwst"

Check warning on line 13 in tests/test_hooks.py

View check run for this annotation

Codecov / codecov/patch

tests/test_hooks.py#L13

Added line #L13 was not covered by tests

def get_crds_parameters(self):
return {}

Check warning on line 16 in tests/test_hooks.py

View check run for this annotation

Codecov / codecov/patch

tests/test_hooks.py#L16

Added line #L16 was not covered by tests

def save(self, filename):
asdf.AsdfFile({"data_id": self.data_id}).write_to(filename)

def __enter__(self):
return self

Check warning on line 22 in tests/test_hooks.py

View check run for this annotation

Codecov / codecov/patch

tests/test_hooks.py#L22

Added line #L22 was not covered by tests

def __exit__(self, *args):
pass

Check warning on line 25 in tests/test_hooks.py

View check run for this annotation

Codecov / codecov/patch

tests/test_hooks.py#L25

Added line #L25 was not covered by tests


class FakeStep(Step):
spec = """
output_ext = string(default='asdf')
"""

@classmethod
def _datamodels_open(cls, init, **kwargs):
return init

Check warning on line 35 in tests/test_hooks.py

View check run for this annotation

Codecov / codecov/patch

tests/test_hooks.py#L35

Added line #L35 was not covered by tests


class ShovelPixelsStep(FakeStep):
class_alias = "shovelpixels"

def process(self, input_data):
self.log.info("Shoveling...")
return input_data


class CancelNoiseStep(Step):
class CancelNoiseStep(FakeStep):
class_alias = "cancelnoise"

def process(self, input_data):
self.log.info("De-noising...")
return input_data


class HookStep(Step):
class HookStep(FakeStep):
class_alias = "myhook"

spec = """
param1 = string(default="bar")
param2 = float(default=1)
output_ext = string(default='asdf')
"""

def process(self, input_data):
Expand All @@ -38,11 +69,19 @@ def process(self, input_data):
class MyPipeline(Pipeline):
class_alias = "mypipeline"

spec = """
output_ext = string(default='asdf')
"""

step_defs = { # noqa: RUF012
"shovelpixels": ShovelPixelsStep,
"cancelnoise": CancelNoiseStep,
}

@classmethod
def _datamodels_open(cls, init, **kwargs):
return init

Check warning on line 83 in tests/test_hooks.py

View check run for this annotation

Codecov / codecov/patch

tests/test_hooks.py#L83

Added line #L83 was not covered by tests

def process(self, input_data):
result = self.shovelpixels(input_data)
result = self.cancelnoise(result)
Expand All @@ -54,15 +93,14 @@ def hook_function(input_data):
import logging

log = logging.getLogger(__name__)
log.info("Running hook_function on data array of size %s", input_data.shape)
log.info("Running hook_function on data %s", input_data.data_id)

return input_data


def test_hook_as_step_class(caplog):
def test_hook_as_step_class(caplog, disable_crds_steppars):
"""Test an imported Step subclass can be a hook"""
datamodels = pytest.importorskip("stdatamodels.jwst.datamodels")
model = datamodels.ImageModel((10, 10))
model = FakeDataModel()

steps = {
"cancelnoise": {
Expand All @@ -77,10 +115,9 @@ def test_hook_as_step_class(caplog):
assert "cancelnoise.myhook" in caplog.text


def test_hook_as_step_instance(caplog):
def test_hook_as_step_instance(caplog, disable_crds_steppars):
"""Test an imported Step subclass instance with parameters can be a hook"""
datamodels = pytest.importorskip("stdatamodels.jwst.datamodels")
model = datamodels.ImageModel((10, 10))
model = FakeDataModel()

steps = {
"shovelpixels": {
Expand All @@ -94,10 +131,9 @@ def test_hook_as_step_instance(caplog):
assert "Running HookStep with foo and 3" in caplog.text


def test_hook_as_string_of_importable_step_class(caplog):
def test_hook_as_string_of_importable_step_class(caplog, disable_crds_steppars):
"""Test a string of a fully-qualified path to Step subclass can be a hook"""
datamodels = pytest.importorskip("stdatamodels.jwst.datamodels")
model = datamodels.ImageModel((10, 10))
model = FakeDataModel()

steps = {
"shovelpixels": {
Expand All @@ -111,10 +147,9 @@ def test_hook_as_string_of_importable_step_class(caplog):
assert "Running HookStep" in caplog.text


def test_hook_as_string_of_step_instance(caplog):
def test_hook_as_string_of_step_instance(caplog, disable_crds_steppars):
"""Test a string of a fully-qualified Step instance w/params"""
datamodels = pytest.importorskip("stdatamodels.jwst.datamodels")
model = datamodels.ImageModel((10, 10))
model = FakeDataModel()

steps = {
"shovelpixels": {
Expand All @@ -128,10 +163,10 @@ def test_hook_as_string_of_step_instance(caplog):
assert "Running HookStep with foo and 2" in caplog.text


def test_hook_as_string_of_importable_function(caplog):
def test_hook_as_string_of_importable_function(caplog, disable_crds_steppars):
"""Test a string of a fully-qualified function path can be a hook"""
datamodels = pytest.importorskip("stdatamodels.jwst.datamodels")
model = datamodels.ImageModel((10, 10))
data_id = 42
model = FakeDataModel(data_id)

steps = {
"shovelpixels": {
Expand All @@ -142,31 +177,26 @@ def test_hook_as_string_of_importable_function(caplog):
}
MyPipeline.call(model, steps=steps)

assert "Running hook_function on data array of size (10, 10)" in caplog.text
assert f"Running hook_function on data {data_id}" in caplog.text


def test_hook_as_systemcall(caplog, tmp_cwd):
def test_hook_as_systemcall(caplog, tmp_cwd, disable_crds_steppars):
"""Test a string of a terminal command"""
datamodels = pytest.importorskip("stdatamodels.jwst.datamodels")
model = datamodels.ImageModel((10, 10))
filename = "test_hook_as_subprocess.fits"
path = tmp_cwd / filename
model.save(path)
model = FakeDataModel()

# Run post_hooks of "fitsinfo" and "fitsheader" CLI scripts from astropy
# Run post_hook CLI scripts
steps = {
"shovelpixels": {
"post_hooks": [
"fitsinfo {0}",
"fitsheader {0}",
"asdftool info {0}",
]
}
}
MyPipeline.call(model, steps=steps)

# Logs from fitsinfo
assert "SystemCall instance created" in caplog.text
assert "Spawning 'fitsinfo stpipe.MyPipeline.shovelpixels.post_hook0" in caplog.text

# logs from fitsheader
assert "DATAMODL= 'ImageModel'" in caplog.text
assert (
"Spawning 'asdftool info stpipe.MyPipeline.shovelpixels.post_hook0"
in caplog.text
)

0 comments on commit 1e50496

Please sign in to comment.