@@ -164,6 +164,7 @@ def test_model(
164164 * ,
165165 determinism : Literal ["seed_only" , "full" ] = "seed_only" ,
166166 sha256 : Optional [Sha256 ] = None ,
167+ stop_early : bool = False ,
167168 ** deprecated : Unpack [DeprecatedKwargs ],
168169) -> ValidationSummary :
169170 """Test model inference"""
@@ -174,6 +175,7 @@ def test_model(
174175 determinism = determinism ,
175176 expected_type = "model" ,
176177 sha256 = sha256 ,
178+ stop_early = stop_early ,
177179 ** deprecated ,
178180 )
179181
@@ -192,13 +194,15 @@ def test_description(
192194 determinism : Literal ["seed_only" , "full" ] = "seed_only" ,
193195 expected_type : Optional [str ] = None ,
194196 sha256 : Optional [Sha256 ] = None ,
197+ stop_early : bool = False ,
195198 runtime_env : Union [
196199 Literal ["currently-active" , "as-described" ], Path , BioimageioCondaEnv
197200 ] = ("currently-active" ),
198201 run_command : Callable [[Sequence [str ]], None ] = default_run_command ,
199202 ** deprecated : Unpack [DeprecatedKwargs ],
200203) -> ValidationSummary :
201- """Test a bioimage.io resource dynamically, e.g. prediction of test tensors for models.
204+ """Test a bioimage.io resource dynamically,
205+ for example run prediction of test tensors for models.
202206
203207 Args:
204208 source: model description source.
@@ -207,6 +211,10 @@ def test_description(
207211 devices: Devices to test with, e.g. 'cpu', 'cuda'.
208212 Default (may be weight format dependent): ['cuda'] if available, ['cpu'] otherwise.
209213 determinism: Modes to improve reproducibility of test outputs.
214+ expected_type: Assert an expected resource description `type`.
215+ sha256: Expected SHA256 value of **source**.
216+ (Ignored if **source** already is a loaded `ResourceDescr` object.)
217+ stop_early: Do not run further subtests after a failed one.
210218 runtime_env: (Experimental feature!) The Python environment to run the tests in
211219 - `"currently-active"`: Use active Python interpreter.
212220 - `"as-described"`: Use `bioimageio.spec.get_conda_env` to generate a conda
@@ -225,6 +233,7 @@ def test_description(
225233 determinism = determinism ,
226234 expected_type = expected_type ,
227235 sha256 = sha256 ,
236+ stop_early = stop_early ,
228237 ** deprecated ,
229238 )
230239 return rd .validation_summary
@@ -254,6 +263,9 @@ def test_description(
254263 conda_env = conda_env ,
255264 devices = devices ,
256265 determinism = determinism ,
266+ expected_type = expected_type ,
267+ sha256 = sha256 ,
268+ stop_early = stop_early ,
257269 run_command = run_command ,
258270 ** deprecated ,
259271 )
@@ -268,6 +280,9 @@ def _test_in_env(
268280 devices : Optional [Sequence [str ]],
269281 determinism : Literal ["seed_only" , "full" ],
270282 run_command : Callable [[Sequence [str ]], None ],
283+ stop_early : bool ,
284+ expected_type : Optional [str ],
285+ sha256 : Optional [Sha256 ],
271286 ** deprecated : Unpack [DeprecatedKwargs ],
272287) -> ValidationSummary :
273288 descr = load_description (source )
@@ -293,6 +308,9 @@ def _test_in_env(
293308 determinism = determinism ,
294309 conda_env = conda_env ,
295310 run_command = run_command ,
311+ expected_type = expected_type ,
312+ sha256 = sha256 ,
313+ stop_early = stop_early ,
296314 ** deprecated ,
297315 )
298316 for wf in all_present_wfs [1 :]:
@@ -304,6 +322,9 @@ def _test_in_env(
304322 determinism = determinism ,
305323 conda_env = conda_env ,
306324 run_command = run_command ,
325+ expected_type = expected_type ,
326+ sha256 = sha256 ,
327+ stop_early = stop_early ,
307328 ** deprecated ,
308329 )
309330 for d in additional_summary .details :
@@ -370,7 +391,10 @@ def _test_in_env(
370391 "test" ,
371392 str (source ),
372393 f"--summary-path={ summary_path } " ,
394+ f"--determinism={ determinism } " ,
373395 ]
396+ + ([f"--expected-type={ expected_type } " ] if expected_type else [])
397+ + (["--stop-early" ] if stop_early else [])
374398 )
375399 return ValidationSummary .model_validate_json (summary_path .read_bytes ())
376400
@@ -385,6 +409,7 @@ def load_description_and_test(
385409 determinism : Literal ["seed_only" , "full" ] = "seed_only" ,
386410 expected_type : Optional [str ] = None ,
387411 sha256 : Optional [Sha256 ] = None ,
412+ stop_early : bool = False ,
388413 ** deprecated : Unpack [DeprecatedKwargs ],
389414) -> Union [LatestResourceDescr , InvalidDescr ]: ...
390415
@@ -399,6 +424,7 @@ def load_description_and_test(
399424 determinism : Literal ["seed_only" , "full" ] = "seed_only" ,
400425 expected_type : Optional [str ] = None ,
401426 sha256 : Optional [Sha256 ] = None ,
427+ stop_early : bool = False ,
402428 ** deprecated : Unpack [DeprecatedKwargs ],
403429) -> Union [ResourceDescr , InvalidDescr ]: ...
404430
@@ -412,9 +438,18 @@ def load_description_and_test(
412438 determinism : Literal ["seed_only" , "full" ] = "seed_only" ,
413439 expected_type : Optional [str ] = None ,
414440 sha256 : Optional [Sha256 ] = None ,
441+ stop_early : bool = False ,
415442 ** deprecated : Unpack [DeprecatedKwargs ],
416443) -> Union [ResourceDescr , InvalidDescr ]:
417- """Test RDF dynamically, e.g. model inference of test inputs"""
444+ """Test a bioimage.io resource dynamically,
445+ for example run prediction of test tensors for models.
446+
447+ See `test_description` for more details.
448+
449+ Returns:
450+ A (possibly invalid) resource description object
451+ with a populated `.validation_summary` attribute.
452+ """
418453 if isinstance (source , ResourceDescrBase ):
419454 root = source .root
420455 file_name = source .file_name
@@ -477,11 +512,15 @@ def load_description_and_test(
477512 enable_determinism (determinism , weight_formats = weight_formats )
478513 for w in weight_formats :
479514 _test_model_inference (rd , w , devices , ** deprecated )
480- if (
481- not isinstance (rd , v0_4 .ModelDescr )
482- and rd .validation_summary .status == "passed"
483- ):
484- _test_model_inference_parametrized (rd , w , devices )
515+ if stop_early and rd .validation_summary .status != "passed" :
516+ break
517+
518+ if not isinstance (rd , v0_4 .ModelDescr ):
519+ _test_model_inference_parametrized (
520+ rd , w , devices , stop_early = stop_early
521+ )
522+ if stop_early and rd .validation_summary .status != "passed" :
523+ break
485524
486525 # TODO: add execution of jupyter notebooks
487526 # TODO: add more tests
@@ -631,6 +670,8 @@ def _test_model_inference_parametrized(
631670 model : v0_5 .ModelDescr ,
632671 weight_format : SupportedWeightsFormat ,
633672 devices : Optional [Sequence [str ]],
673+ * ,
674+ stop_early : bool ,
634675) -> None :
635676 if not any (
636677 isinstance (a .size , v0_5 .ParameterizedSize )
@@ -772,6 +813,8 @@ def get_ns(n: int):
772813 ),
773814 )
774815 )
816+ if stop_early and error is not None :
817+ break
775818 except Exception as e :
776819 if validation_context_var .get ().raise_errors :
777820 raise e
0 commit comments