Skip to content

Commit c4b533c

Browse files
authored
Merge pull request #708 from bioimage-io/float_update
Disallow inf and nan values throughout the spec
2 parents ac33ad5 + f4b324e commit c4b533c

File tree

8 files changed

+54
-8
lines changed

8 files changed

+54
-8
lines changed

.vscode/settings.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,12 @@
1515
"bioimageio.yaml",
1616
"*.bioimageio.yaml"
1717
],
18-
}
18+
},
19+
"python-envs.pythonProjects": [
20+
{
21+
"path": "",
22+
"envManager": "ms-python.python:conda",
23+
"packageManager": "ms-python.python:conda"
24+
}
25+
]
1926
}

bioimageio/spec/_internal/io_utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import numpy
2121
from loguru import logger
2222
from numpy.typing import NDArray
23-
from pydantic import FilePath, NewPath, RootModel
23+
from pydantic import BaseModel, FilePath, NewPath, RootModel
2424
from ruyaml import YAML
2525
from typing_extensions import Unpack
2626

@@ -70,7 +70,7 @@ def read_yaml(
7070

7171

7272
def write_yaml(
73-
content: Union[YamlValue, BioimageioYamlContentView],
73+
content: Union[YamlValue, BioimageioYamlContentView, BaseModel],
7474
/,
7575
file: Union[NewPath, FilePath, IO[str], IO[bytes], ZipPath],
7676
):
@@ -79,6 +79,9 @@ def write_yaml(
7979
else:
8080
cm = nullcontext(file)
8181

82+
if isinstance(content, BaseModel):
83+
content = content.model_dump(mode="json")
84+
8285
with cm as f:
8386
_yaml_dump.dump(content, f)
8487

bioimageio/spec/_internal/node.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,16 @@ def _node_title_generator(node: Type[Node]) -> str:
2727

2828
class Node(
2929
pydantic.BaseModel,
30+
allow_inf_nan=False,
3031
extra="forbid",
3132
frozen=False,
33+
model_title_generator=_node_title_generator,
3234
populate_by_name=True,
3335
revalidate_instances="never",
36+
use_attribute_docstrings=True,
3437
validate_assignment=True,
3538
validate_default=False,
3639
validate_return=True, # TODO: check if False here would bring a speedup and can still be safe
37-
use_attribute_docstrings=True,
38-
model_title_generator=_node_title_generator,
3940
):
4041
"""""" # empty docstring to remove all pydantic docstrings from the pdoc spec docs
4142

bioimageio/spec/_internal/url.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ def _validate_url(url: Union[str, pydantic.HttpUrl]) -> pydantic.HttpUrl:
1717
return _validate_url_impl(url, request_mode="head")
1818

1919

20+
_KNOWN_VALID_URLS = ("https://zenodo.org/records/3446812/files/unet2d_weights.torch",)
21+
"""known valid urls to bypass validation for to avoid sporadic 503 errors in tests etc."""
22+
23+
2024
def _validate_url_impl(
2125
url: Union[str, pydantic.HttpUrl],
2226
request_mode: Literal["head", "get_stream", "get"],
@@ -30,7 +34,11 @@ def _validate_url_impl(
3034

3135
val_url = url
3236

33-
if url.startswith("http://example.com") or url.startswith("https://example.com"):
37+
if (
38+
url.startswith("http://example.com")
39+
or url.startswith("https://example.com")
40+
or url in _KNOWN_VALID_URLS
41+
):
3442
return pydantic.HttpUrl(url)
3543

3644
if url.startswith("https://colab.research.google.com/github/"):

bioimageio/spec/model/v0_5.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
)
7777
from .._internal.io_utils import load_array
7878
from .._internal.node_converter import Converter
79+
from .._internal.type_guards import is_dict, is_sequence
7980
from .._internal.types import (
8081
AbsoluteTolerance,
8182
LowerCaseIdentifier,
@@ -878,6 +879,27 @@ class IntervalOrRatioDataDescr(Node):
878879
offset: Optional[float] = None
879880
"""Offset for data on a ratio scale."""
880881

882+
@model_validator(mode="before")
883+
def _replace_inf(cls, data: Any):
884+
if is_dict(data):
885+
if "range" in data and is_sequence(data["range"]):
886+
forbidden = (
887+
"inf",
888+
"-inf",
889+
".inf",
890+
"-.inf",
891+
float("inf"),
892+
float("-inf"),
893+
)
894+
if any(v in forbidden for v in data["range"]):
895+
issue_warning("replaced 'inf' value", value=data["range"])
896+
897+
data["range"] = tuple(
898+
(None if v in forbidden else v) for v in data["range"]
899+
)
900+
901+
return data
902+
881903

882904
TensorDataDescr = Union[NominalOrOrdinalDataDescr, IntervalOrRatioDataDescr]
883905

changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ In this file we log both:
1010

1111
This changelog includes implementation details and my reference the [changes to the Resource Description Format](#changes-to-the-resource-description-format), e.g. in entry [bioimageio.spec 0.5.2](#bioimageiospec-052).
1212

13+
#### bioimageio.spec (next release)
14+
15+
- infinity and not-a-number values are no longer allowed (when used in a tensor description under data.range they are replaced with `None`)
16+
1317
#### bioimageio.spec 0.5.4.3
1418

1519
- fix root determination of cacheless downloads of non-zip files

tests/test_bioimageio_collection.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"philosophical-panda/0.1.0": {"outputs"}, # int -> float
2727
"polite-pig/1.1": {"inputs", "outputs"},
2828
"charismatic-whale/1.0.2": {"inputs", "outputs"}, # int -> float
29+
"dynamic-t-rex/1.1": {"inputs"}, # int -> float
2930
}
3031

3132

tests/test_model/test_v0_5.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def test_tensor_base_invalid(kwargs: Dict[str, Any]):
129129
{
130130
"id": "input_1",
131131
"description": "Input 1",
132-
"data": {"type": "float32"},
132+
"data": {"type": "float32", "range": ["-inf", float("inf")]},
133133
"axes": [
134134
dict(type="space", id="x", size=10),
135135
dict(type="space", id="y", size=11),
@@ -146,7 +146,7 @@ def test_tensor_base_invalid(kwargs: Dict[str, Any]):
146146
}
147147
],
148148
"test_tensor": {"source": UNET2D_ROOT / "test_input.npy"},
149-
},
149+
}
150150
],
151151
)
152152
def test_input_tensor(kwargs: Dict[str, Any]):

0 commit comments

Comments
 (0)