diff --git a/bioimageio/spec/_internal/types/_file_source.py b/bioimageio/spec/_internal/types/_file_source.py index 371f96ae4..0109c18e0 100644 --- a/bioimageio/spec/_internal/types/_file_source.py +++ b/bioimageio/spec/_internal/types/_file_source.py @@ -17,6 +17,8 @@ from pydantic_core import core_schema from typing_extensions import Annotated +from bioimageio.spec._internal.validation_context import get_internal_validation_context + class RelativePath: path: PurePosixPath @@ -95,9 +97,9 @@ def _validate(cls, value: Union[pathlib.Path, str], info: ValidationInfo): if ret.path.is_absolute(): raise ValueError(f"{value} is an absolute path.") - root = (info.context or {}).get("root") - if root is not None: - ret._check_exists(root) + context = get_internal_validation_context(info.context) + if context["perform_io_checks"]: + ret._check_exists(context["root"]) return ret diff --git a/tests/conftest.py b/tests/conftest.py index 469d056bf..1d00cf1fd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,6 +8,8 @@ EXAMPLE_SPECS = Path(__file__).parent / "../example_specs" +UNET2D_ROOT = EXAMPLE_SPECS / "models/unet2d_nuclei_broad" + @pytest.fixture(scope="session") def stardist04_data(): @@ -17,12 +19,13 @@ def stardist04_data(): @pytest.fixture(scope="session") def unet2d_root() -> Path: - return EXAMPLE_SPECS / "models/unet2d_nuclei_broad" + """deprecated, use constant UNET2D_ROOT instead""" + return UNET2D_ROOT @pytest.fixture(scope="session") -def unet2d_data(unet2d_root: Path): - with (unet2d_root / "rdf.yaml").open() as f: +def unet2d_data(): + with (UNET2D_ROOT / "rdf.yaml").open() as f: data = yaml.load(f) return MappingProxyType(data) diff --git a/tests/test_description.py b/tests/test_description.py index aafe79078..370ef111c 100644 --- a/tests/test_description.py +++ b/tests/test_description.py @@ -1,6 +1,6 @@ from pydantic import HttpUrl -from bioimageio.spec._description import build_description, validate_format +from bioimageio.spec._description import validate_format from bioimageio.spec._internal.types import BioimageioYamlContent from bioimageio.spec._internal.validation_context import ValidationContext @@ -10,10 +10,10 @@ def test_forward_compatibility(unet2d_data: BioimageioYamlContent): v_future = "9999.0.0" data["format_version"] = v_future # assume it is valid in a future format version - summary = build_description( + summary = validate_format( data, context=ValidationContext(root=HttpUrl("https://example.com/"), perform_io_checks=False) - ).validation_summaries[0] - assert summary.status == "passed", summary + ) + assert summary.status == "passed", summary.errors # expect warning about treating future format version as latest ws = summary.warnings diff --git a/tests/test_generic/test_v0_3.py b/tests/test_generic/test_v0_3.py index d8fa592d0..16c247944 100644 --- a/tests/test_generic/test_v0_3.py +++ b/tests/test_generic/test_v0_3.py @@ -1,12 +1,16 @@ from __future__ import annotations from pathlib import Path -from typing import Any, Dict +from typing import Any, Dict, Union import pytest from bioimageio.spec._internal.constants import WARNING -from bioimageio.spec._internal.validation_context import ValidationContext, get_internal_validation_context +from bioimageio.spec._internal.validation_context import ( + InternalValidationContext, + ValidationContext, + get_internal_validation_context, +) from bioimageio.spec.generic.v0_3 import Generic from tests.utils import check_node @@ -42,7 +46,7 @@ ], ) def test_generic_valid(kwargs: Dict[str, Any]): - check_node(Generic, kwargs) + check_node(Generic, kwargs, context=ValidationContext(perform_io_checks=False)) @pytest.mark.parametrize( @@ -59,12 +63,12 @@ def test_generic_valid(kwargs: Dict[str, Any]): license="BSD-2-Clause-FreeBSD", cite=[dict(text="lala", url=EXAMPLE_DOT_COM)], ), - get_internal_validation_context(warning_level=WARNING), + get_internal_validation_context(warning_level=WARNING, perform_io_checks=False), id="deprecated license", ), ( dict(format_version=Generic.implemented_format_version, version="0.1.0", type="my_type", name="their name"), - {}, + ValidationContext(perform_io_checks=False), ), ( dict( @@ -74,9 +78,9 @@ def test_generic_valid(kwargs: Dict[str, Any]): name="its name", attachments={"files": [Path(__file__), "missing"], "something": 42}, ), - {}, + ValidationContext(perform_io_checks=False), ), ], ) -def test_generic_invalid(kwargs: Dict[str, Any], context: ValidationContext): +def test_generic_invalid(kwargs: Dict[str, Any], context: Union[ValidationContext, InternalValidationContext]): check_node(Generic, kwargs, context=context, is_invalid=True) diff --git a/tests/test_model/test_v0_4.py b/tests/test_model/test_v0_4.py index c48d7ae22..bd7e19c09 100644 --- a/tests/test_model/test_v0_4.py +++ b/tests/test_model/test_v0_4.py @@ -1,4 +1,5 @@ from datetime import datetime +from pathlib import Path from typing import Any, Dict, Union import pytest @@ -17,7 +18,6 @@ OutputTensor, Postprocessing, Preprocessing, - RelativeFilePath, ScaleLinearKwargs, ScaleMeanVariance, ScaleRange, @@ -25,6 +25,7 @@ TensorName, Weights, ) +from tests.conftest import UNET2D_ROOT from tests.utils import check_node, check_type, unset @@ -47,16 +48,12 @@ def test_linked_model_invalid(kwargs: Dict[str, Any]): "kwargs,expected", [ ( - dict(opset_version=8, source="https://example.com", sha256="s" * 64), - dict(opset_version=8, source="https://example.com/", sha256="s" * 64), + dict(source=UNET2D_ROOT / "weights.onnx", sha256="s" * 64), + dict(source=UNET2D_ROOT / "weights.onnx", sha256="s" * 64), ), + (dict(opset_version=5, source=UNET2D_ROOT / "weights.onnx", sha256="s" * 64), ValidationError), ( - dict(source="https://example.com", sha256="s" * 64), - dict(source="https://example.com/", sha256="s" * 64), - ), - (dict(opset_version=5, source="https://example.com", sha256="s" * 64), ValidationError), - ( - dict(source="https://example.com", sha256="s"), + dict(source=UNET2D_ROOT / "weights.onnx", sha256="s"), ValidationError, ), ], @@ -237,9 +234,9 @@ def test_output_tensor(kwargs: Dict[str, Any]): @pytest.fixture -def model_data(): +def model_data(unet2d_root: Path): return Model( - documentation=RelativeFilePath("docs.md"), + documentation=unet2d_root / "README.md", license="MIT", git_repo="https://github.com/bioimage-io/python-bioimage-io", format_version="0.4.9", @@ -274,9 +271,9 @@ def model_data(): ], name="Model", tags=[], - weights=Weights(onnx=OnnxWeights(source=RelativeFilePath("weights.onnx"))), - test_inputs=[RelativeFilePath("test_ipt.npy")], - test_outputs=[RelativeFilePath("test_out.npy")], + weights=Weights(onnx=OnnxWeights(source=unet2d_root / "weights.onnx")), + test_inputs=[unet2d_root / "test_ipt.npy"], + test_outputs=[unet2d_root / "test_out.npy"], type="model", ).model_dump() @@ -304,17 +301,13 @@ def model_data(): ) def test_model(model_data: Dict[str, Any], update: Dict[str, Any]): model_data.update(update) - summary = validate_format( - model_data, context=ValidationContext(root=HttpUrl("https://example.com/"), perform_io_checks=False) - ) + summary = validate_format(model_data, context=ValidationContext(perform_io_checks=False)) assert summary.status == "passed", summary.format() def test_warn_long_name(model_data: Dict[str, Any]): model_data["name"] = "veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery loooooooooooooooong name" - summary = validate_format( - model_data, context=ValidationContext(root=HttpUrl("https://example.com/"), perform_io_checks=False) - ) + summary = validate_format(model_data, context=ValidationContext(perform_io_checks=False)) assert summary.status == "passed", summary.format() assert summary.warnings[0].loc == ("name",), summary.format() assert summary.warnings[0].msg in "Name longer than 64 characters." diff --git a/tests/test_model/test_v0_5.py b/tests/test_model/test_v0_5.py index 7c4291bcc..2da742599 100644 --- a/tests/test_model/test_v0_5.py +++ b/tests/test_model/test_v0_5.py @@ -1,8 +1,8 @@ from datetime import datetime +from pathlib import Path from typing import Any, Dict, Union import pytest -from pydantic import HttpUrl from bioimageio.spec._description import validate_format from bioimageio.spec._internal.validation_context import ValidationContext @@ -24,6 +24,7 @@ TensorId, Weights, ) +from tests.conftest import UNET2D_ROOT from tests.utils import check_node, check_type @@ -32,12 +33,12 @@ [ dict( id="t1", - test_tensor="https://example.com/test.npy", + test_tensor=UNET2D_ROOT / "test_input.npy", data={"values": ["cat", "dog", "parrot"]}, ), dict( id="t2", - test_tensor="https://example.com/test.npy", + test_tensor=UNET2D_ROOT / "test_input.npy", data=[ {"values": ["cat", "dog", "parrot"]}, {"values": ["mouse", "zebra", "elephant"]}, @@ -45,7 +46,7 @@ ), dict( id="t3", - test_tensor="https://example.com/test.npy", + test_tensor=UNET2D_ROOT / "test_input.npy", data=[ {"values": [1, 2, 3]}, {"type": "uint8"}, @@ -54,7 +55,7 @@ pytest.param( dict( id="t4", - test_tensor="https://example.com/test.npy", + test_tensor=UNET2D_ROOT / "test_input.npy", data=[ {"values": ["mouse", "zebra", "elephant"]}, {"type": "uint8"}, @@ -74,7 +75,7 @@ def test_tensor_base(kwargs: Dict[str, Any]): pytest.param( dict( id="t5", - test_tensor="https://example.com/test.npy", + test_tensor=UNET2D_ROOT / "test_input.npy", data=[ {"values": ["cat", "dog", "parrot"]}, {"values": [1.1, 2.2, 3.3]}, @@ -85,7 +86,7 @@ def test_tensor_base(kwargs: Dict[str, Any]): pytest.param( dict( id="t7", - test_tensor="https://example.com/test.npy", + test_tensor=UNET2D_ROOT / "test.npy", data=[ {"values": ["mouse", "zebra", "elephant"]}, {"type": "int8"}, @@ -117,7 +118,7 @@ def test_tensor_base_invalid(kwargs: Dict[str, Any]): "kwargs": {"max_percentile": 99, "min_percentile": 5, "mode": "per_sample", "axes": ("x", "y")}, } ], - "test_tensor": "https://example.com/test.npy", + "test_tensor": UNET2D_ROOT / "test_input.npy", }, ], ) @@ -131,7 +132,7 @@ def test_input_tensor(kwargs: Dict[str, Any]): pytest.param( dict( id="input_2", - test_tensor="https://example.com/test.npy", + test_tensor=UNET2D_ROOT / "test.npy", data=[ {"values": ["cat", "dog", "parrot"]}, {"values": ["mouse", "zebra", "elephant"]}, @@ -169,9 +170,9 @@ def test_input_axis(kwargs: Union[Dict[str, Any], SpaceInputAxis]): @pytest.fixture -def model_data(): +def model_data(unet2d_root: Path): data = Model( - documentation=HttpUrl("https://example.com/docs.md"), + documentation=unet2d_root / "README.md", license="MIT", git_repo="https://github.com/bioimage-io/python-bioimage-io", format_version="0.5.0", @@ -196,7 +197,7 @@ def model_data(): SpaceInputAxis(id=AxisId("y"), size=20), ChannelAxis(size=3), ], - test_tensor=HttpUrl("https://example.com/test_ipt.npy"), + test_tensor=unet2d_root / "test_ipt.npy", ), ], outputs=[ @@ -208,17 +209,14 @@ def model_data(): SpaceOutputAxis(id=AxisId("y"), size=25), ChannelAxis(size=6), ], - test_tensor=HttpUrl("https://example.com/test_out.npy"), + test_tensor=unet2d_root / "test_out.npy", ), ], name="Model", tags=[], - weights=Weights(onnx=OnnxWeights(source=HttpUrl("https://example.com/weights.onnx"), opset_version=15)), + weights=Weights(onnx=OnnxWeights(source=unet2d_root / "weights.onnx", opset_version=15)), type="model", ).model_dump() - # make data more editable - data["outputs"] = list(data["outputs"]) - data["outputs"][0]["axes"] = list(data["outputs"][0]["axes"]) return data @@ -227,19 +225,19 @@ def model_data(): [ pytest.param(dict(name="ยต-unicode-model/name!"), id="unicode name"), dict(run_mode={"name": "special_run_mode", "kwargs": dict(marathon=True)}), - dict(weights={"torchscript": {"source": "https://example.com/weights", "pytorch_version": 1.15}}), - dict(weights={"keras_hdf5": {"source": "https://example.com/weights", "tensorflow_version": 1.10}}), - dict(weights={"tensorflow_js": {"source": "https://example.com/weights", "tensorflow_version": 1.10}}), + dict(weights={"torchscript": {"source": UNET2D_ROOT / "weights.onnx", "pytorch_version": 1.15}}), + dict(weights={"keras_hdf5": {"source": UNET2D_ROOT / "weights.onnx", "tensorflow_version": 1.10}}), + dict(weights={"tensorflow_js": {"source": UNET2D_ROOT / "weights.onnx", "tensorflow_version": 1.10}}), dict( weights={ - "tensorflow_saved_model_bundle": {"source": "https://example.com/weights", "tensorflow_version": 1.10} + "tensorflow_saved_model_bundle": {"source": UNET2D_ROOT / "weights.onnx", "tensorflow_version": 1.10} } ), - dict(weights={"onnx": {"source": "https://example.com/weights", "opset_version": 15}}), + dict(weights={"onnx": {"source": UNET2D_ROOT / "weights.onnx", "opset_version": 15}}), dict( weights={ "pytorch_state_dict": { - "source": "https://example.com/weights", + "source": UNET2D_ROOT / "weights.onnx", "pytorch_version": "1.15", "architecture": { "callable": "https://example.com/file.py:Model",