Skip to content

Commit 7cfa502

Browse files
authored
Merge pull request #267 from bioimage-io/extend_test_resources
Extend test resources
2 parents 6ed4c54 + 9c073ce commit 7cfa502

File tree

8 files changed

+283
-132
lines changed

8 files changed

+283
-132
lines changed

bioimageio/core/__main__.py

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
import json
33
import os
44
import sys
5+
import warnings
56
from glob import glob
67

78
from pathlib import Path
8-
from pprint import pprint
9+
from pprint import pformat, pprint
910
from typing import List, Optional
1011

1112
import typer
1213

1314
from bioimageio.core import __version__, prediction, commands, resource_tests, load_raw_resource_description
15+
from bioimageio.core.common import TestSummary
1416
from bioimageio.core.prediction_pipeline import get_weight_formats
1517
from bioimageio.spec.__main__ import app, help_version as help_version_spec
1618
from bioimageio.spec.model.raw_nodes import WeightsFormat
@@ -21,12 +23,16 @@
2123
from typing_extensions import get_args # type: ignore
2224

2325
try:
24-
from bioimageio.core.weight_converter import torch as torch_converter
26+
with warnings.catch_warnings():
27+
warnings.simplefilter("ignore")
28+
from bioimageio.core.weight_converter import torch as torch_converter
2529
except ImportError:
2630
torch_converter = None
2731

2832
try:
29-
from bioimageio.core.weight_converter import keras as keras_converter
33+
with warnings.catch_warnings():
34+
warnings.simplefilter("ignore")
35+
from bioimageio.core.weight_converter import keras as keras_converter
3036
except ImportError:
3137
keras_converter = None
3238

@@ -78,6 +84,46 @@ def package(
7884
# WeightFormatEnum = enum.Enum("WeightFormatEnum", get_args(WeightsFormat))
7985

8086

87+
def _log_test_summaries(summaries: List[TestSummary], msg: str):
88+
# todo: improve logging of multiple test summaries
89+
ret_code = 0
90+
for summary in summaries:
91+
print(f"{summary['name']}: {summary['status']}")
92+
if summary["status"] != "passed":
93+
s = {
94+
k: v
95+
for k, v in summary.items()
96+
if k not in ("name", "status", "bioimageio_spec_version", "bioimageio_core_version")
97+
}
98+
tb = s.pop("traceback")
99+
if tb:
100+
print("traceback:")
101+
print("".join(tb))
102+
103+
def show_part(part, show):
104+
if show:
105+
line = f"{part}: "
106+
print(line + pformat(show, width=min(80, 120 - len(line))).replace("\n", " " * len(line) + "\n"))
107+
108+
for part in ["error", "warnings", "source_name"]:
109+
show_part(part, s.pop(part, None))
110+
111+
for part in sorted(s.keys()):
112+
show_part(part, s[part])
113+
114+
ret_code = 1
115+
116+
if ret_code:
117+
result = "FAILED!"
118+
icon = "❌"
119+
else:
120+
result = "passed."
121+
icon = "✔️"
122+
123+
print(msg.format(icon=icon, result=result))
124+
return ret_code
125+
126+
81127
@app.command()
82128
def test_model(
83129
model_rdf: str = typer.Argument(
@@ -88,31 +134,16 @@ def test_model(
88134
decimal: int = typer.Option(4, help="The test precision."),
89135
):
90136
# this is a weird typer bug: default devices are empty tuple although they should be None
91-
if len(devices) == 0:
92-
devices = None
93-
summary = resource_tests.test_model(
137+
devices = devices or None
138+
139+
summaries = resource_tests.test_model(
94140
model_rdf,
95141
weight_format=None if weight_format is None else weight_format.value,
96142
devices=devices,
97143
decimal=decimal,
98144
)
99-
100-
if weight_format is None:
101-
weight_formats = get_weight_formats()
102-
model_weight_formats = list(load_raw_resource_description(model_rdf).weights.keys())
103-
for wf in weight_formats:
104-
if wf in model_weight_formats:
105-
weight_format = wf
106-
break
107-
weight_format = "unknown" if weight_format is None else weight_format
108-
109-
if summary["error"] is None:
110-
print(f"Model test for {model_rdf} using {weight_format} weight format has passed.")
111-
ret_code = 0
112-
else:
113-
print(f"Model test for {model_rdf} using {weight_format} weight format has FAILED!")
114-
pprint(summary)
115-
ret_code = 1
145+
print(f"\ntesting model {model_rdf}...")
146+
ret_code = _log_test_summaries(summaries, f"\n{{icon}} Model {model_rdf} {{result}}")
116147
sys.exit(ret_code)
117148

118149

@@ -131,16 +162,11 @@ def test_resource(
131162
# this is a weird typer bug: default devices are empty tuple although they should be None
132163
if len(devices) == 0:
133164
devices = None
134-
summary = resource_tests.test_resource(
165+
summaries = resource_tests.test_resource(
135166
rdf, weight_format=None if weight_format is None else weight_format.value, devices=devices, decimal=decimal
136167
)
137-
if summary["error"] is None:
138-
print(f"Resource test for {rdf} has passed.")
139-
ret_code = 0
140-
else:
141-
print(f"Resource test for {rdf} has FAILED!")
142-
pprint(summary)
143-
ret_code = 1
168+
print(f"\ntesting {rdf}...")
169+
ret_code = _log_test_summaries(summaries, f"{{icon}} Resource test for {rdf} has {{result}}")
144170
sys.exit(ret_code)
145171

146172

bioimageio/core/build_spec/add_weights.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ def add_weights(
3838
attachments: extra weight specific attachments.
3939
"""
4040
model = load_raw_resource_description(model)
41+
if not isinstance(model.root_path, Path):
42+
# ensure model is available locally
43+
model = load_raw_resource_description(export_resource_package(model))
44+
45+
assert isinstance(model.root_path, Path), model.root_path
4146

4247
# copy the weight path to the input model's root, otherwise it will
4348
# not be found when packaging the new model

bioimageio/core/common.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from bioimageio.spec.shared.common import ValidationSummary
2+
3+
4+
class TestSummary(ValidationSummary):
5+
bioimageio_core_version: str

bioimageio/core/prediction.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,23 @@ def load_tile(tile):
129129

130130
def predict(
131131
prediction_pipeline: PredictionPipeline,
132-
inputs: Union[xr.DataArray, List[xr.DataArray], Tuple[xr.DataArray]],
132+
inputs: Union[
133+
xr.DataArray, List[xr.DataArray], Tuple[xr.DataArray], np.ndarray, List[np.ndarray], Tuple[np.ndarray]
134+
],
133135
) -> List[xr.DataArray]:
134136
"""Run prediction for a single set of input(s) with a bioimage.io model
135137
136138
Args:
137139
prediction_pipeline: the prediction pipeline for the input model.
138-
inputs: the input(s) for this model represented as xarray data.
140+
inputs: the input(s) for this model represented as xarray data or numpy nd array.
139141
"""
140142
if not isinstance(inputs, (tuple, list)):
141143
inputs = [inputs]
142144

143145
assert len(inputs) == len(prediction_pipeline.input_specs)
144146
tagged_data = [
145-
xr.DataArray(ipt, dims=ipt_spec.axes) for ipt, ipt_spec in zip(inputs, prediction_pipeline.input_specs)
147+
ipt if isinstance(ipt, xr.DataArray) else xr.DataArray(ipt, dims=ipt_spec.axes)
148+
for ipt, ipt_spec in zip(inputs, prediction_pipeline.input_specs)
146149
]
147150
return prediction_pipeline.forward(*tagged_data)
148151

0 commit comments

Comments
 (0)