"""Composite behavior: substitution, ordering, metadata, and adapters.""" import json import numpy as np import pytest from image_filter import ( CannyFilter, GaussianFilter, ImageFilter, ImageItem, InvalidConfigurationError, MeanFilter, Pipeline, SliceWise, SobelFilter, UnsupportedDimensionError, ) def test_nested_pipeline_matches_explicit_execution_and_preserves_metadata(): image = np.arange(120, dtype=float).reshape(10, 12) metadata = {"patient": {"label": "test"}} first, second, third = MeanFilter(3), GaussianFilter(0.8), SobelFilter() operation = Pipeline([Pipeline([first, second]), third]) assert isinstance(operation, ImageFilter) result = operation.apply(image, metadata) expected = third.apply(second.apply(first.apply(image).image).image) np.testing.assert_array_equal(result.image, expected.image) assert [x["filter"] for x in result.metadata["processing_history"]] == [ "MeanFilter", "GaussianFilter", "SobelFilter", ] assert metadata == {"patient": {"label": "test"}} assert result.metadata["patient"] is not metadata["patient"] np.testing.assert_array_equal(image, np.arange(120).reshape(10, 12)) for component in (first, operation): batch = component.apply_batch([ImageItem(image), ImageItem(image[None])]) np.testing.assert_array_equal(batch[0].image, batch[1].image[0]) def test_pipeline_in_slicewise_preserves_boolean_output_and_serializable_history(): volume = np.random.default_rng(12).random((10, 12, 5)) pipeline = Pipeline([GaussianFilter(0.8), CannyFilter(use_quantiles=True)]) result = SliceWise(pipeline, axis=2).apply(volume) expected = np.stack([pipeline.apply(volume[:, :, i]).image for i in range(5)], axis=2) np.testing.assert_array_equal(result.image, expected) assert result.image.dtype == bool json.dumps(dict(result.metadata)) assert pipeline.capabilities.spatial_dimensions == frozenset({2}) with pytest.raises(UnsupportedDimensionError): pipeline.apply(volume) def test_invalid_composites_fail_at_construction(): for steps in ([], [object()], [Pipeline([MeanFilter()]), "invalid"]): with pytest.raises(InvalidConfigurationError): Pipeline(steps) with pytest.raises(InvalidConfigurationError): SliceWise(object(), axis=0)