5656 update_format ,
5757 update_hashes ,
5858)
59+ from bioimageio .spec ._internal .io import is_yaml_value
5960from bioimageio .spec ._internal .io_basics import ZipPath
60- from bioimageio .spec ._internal .io_utils import yaml
61+ from bioimageio .spec ._internal .io_utils import open_bioimageio_yaml
6162from bioimageio .spec ._internal .types import NotEmpty
6263from bioimageio .spec .dataset import DatasetDescr
6364from bioimageio .spec .model import ModelDescr , v0_4 , v0_5
6465from bioimageio .spec .notebook import NotebookDescr
65- from bioimageio .spec .utils import download , ensure_description_is_model
66+ from bioimageio .spec .utils import download , ensure_description_is_model , write_yaml
6667
67- from .commands import (
68- WeightFormatArgAll ,
69- WeightFormatArgAny ,
70- package ,
71- test ,
72- )
68+ from .commands import WeightFormatArgAll , WeightFormatArgAny , package , test
7369from .common import MemberId , SampleId , SupportedWeightsFormat
7470from .digest_spec import get_member_ids , load_sample_for_model
7571from .io import load_dataset_stat , save_dataset_stat , save_sample
8379)
8480from .sample import Sample
8581from .stat_measures import Stat
86- from .utils import VERSION
82+ from .utils import VERSION , compare
8783from .weight_converters ._add_weights import add_weights
8884
8985
@@ -193,7 +189,7 @@ def run(self):
193189 )
194190
195191
196- class PackageCmd (CmdBase , WithSource ):
192+ class PackageCmd (CmdBase , WithSource , WithSummaryLogging ):
197193 """Save a resource's metadata with its associated files."""
198194
199195 path : CliPositionalArg [Path ]
@@ -206,10 +202,8 @@ class PackageCmd(CmdBase, WithSource):
206202
207203 def run (self ):
208204 if isinstance (self .descr , InvalidDescr ):
209- paths = self .descr .validation_summary .log ()
210- raise ValueError (
211- f"Invalid { self .descr .type } description. Logged details to { paths } "
212- )
205+ self .log (self .descr )
206+ raise ValueError (f"Invalid { self .descr .type } description." )
213207
214208 sys .exit (
215209 package (
@@ -258,6 +252,12 @@ class UpdateCmdBase(CmdBase, WithSource, ABC):
258252 output : Union [Literal ["render" , "stdout" ], Path ] = "render"
259253 """Output updated bioimageio.yaml to the terminal or write to a file."""
260254
255+ diff : Union [bool , Path ] = Field (True , alias = "diff" )
256+ """Output a diff of original and updated bioimageio.yaml.
257+ If a given path has an `.html` extension, a standalone HTML file is written,
258+ otherwise the diff is saved in unified diff format (pure text).
259+ """
260+
261261 exclude_unset : bool = Field (True , alias = "exclude-unset" )
262262 """Exclude fields that have not explicitly be set."""
263263
@@ -269,29 +269,50 @@ def updated(self) -> Union[ResourceDescr, InvalidDescr]:
269269 raise NotImplementedError
270270
271271 def run (self ):
272- if self .output == "render" :
273- out = StringIO ()
274- elif self .output == "stdout" :
275- out = sys .stdout
276- else :
277- out = self .output
272+ original_yaml = open_bioimageio_yaml (self .source ).local_source .read_text (
273+ encoding = "utf-8"
274+ )
275+ assert isinstance (original_yaml , str )
276+ stream = StringIO ()
278277
279278 save_bioimageio_yaml_only (
280279 self .updated ,
281- out ,
280+ stream ,
282281 exclude_unset = self .exclude_unset ,
283282 exclude_defaults = self .exclude_defaults ,
284283 )
284+ updated_yaml = stream .getvalue ()
285+
286+ diff = compare (
287+ original_yaml .split ("\n " ),
288+ updated_yaml .split ("\n " ),
289+ diff_format = (
290+ "html"
291+ if isinstance (self .diff , Path ) and self .diff .suffix == ".html"
292+ else "unified"
293+ ),
294+ )
285295
286- if self .output == "render" :
287- assert isinstance (out , StringIO )
288- updated_md = f"```yaml\n { out .getvalue ()} \n ```"
296+ if isinstance (self .diff , Path ):
297+ _ = self .diff .write_text (diff , encoding = "utf-8" )
298+ elif self .diff :
299+ diff_md = f"````````diff\n { diff } \n ````````"
300+ rich .console .Console ().print (rich .markdown .Markdown (diff_md ))
289301
290- rich_markdown = rich .markdown .Markdown (updated_md )
291- console = rich .console .Console ()
292- console .print (rich_markdown )
293- elif self .output != "stdout" :
302+ if isinstance (self .output , Path ):
303+ _ = self .output .write_text (updated_yaml , encoding = "utf-8" )
294304 logger .info (f"written updated description to { self .output } " )
305+ elif self .output == "render" :
306+ updated_md = f"```yaml\n { updated_yaml } \n ```"
307+ rich .console .Console ().print (rich .markdown .Markdown (updated_md ))
308+ elif self .output == "stdout" :
309+ print (updated_yaml )
310+ else :
311+ assert_never (self .output )
312+
313+ if isinstance (self .updated , InvalidDescr ):
314+ logger .warning ("Update resulted in invalid description" )
315+ _ = self .updated .validation_summary .display ()
295316
296317
297318class UpdateFormatCmd (UpdateCmdBase ):
@@ -339,7 +360,7 @@ class PredictCmd(CmdBase, WithSource):
339360
340361 Example inputs to process sample 'a' and 'b'
341362 for a model expecting a 'raw' and a 'mask' input tensor:
342- --inputs="[[\" a_raw.tif\" ,\" a_mask.tif\" ],[\" b_raw.tif\" ,\" b_mask.tif\" ]]"
363+ --inputs="[[\\ "a_raw.tif\\ ",\\ "a_mask.tif\\ "],[\\ "b_raw.tif\\ ",\\ "b_mask.tif\ \ "]]"
343364 (Note that JSON double quotes need to be escaped.)
344365
345366 Alternatively a `bioimageio-cli.yaml` (or `bioimageio-cli.json`) file
@@ -435,13 +456,15 @@ def _example(self):
435456 bioimageio_cli_path = example_path / YAML_FILE
436457 stats_file = "dataset_statistics.json"
437458 stats = (example_path / stats_file ).as_posix ()
438- yaml .dump (
439- dict (
440- inputs = inputs ,
441- outputs = output_pattern ,
442- stats = stats_file ,
443- blockwise = self .blockwise ,
444- ),
459+ cli_example_args = dict (
460+ inputs = inputs ,
461+ outputs = output_pattern ,
462+ stats = stats_file ,
463+ blockwise = self .blockwise ,
464+ )
465+ assert is_yaml_value (cli_example_args )
466+ write_yaml (
467+ cli_example_args ,
445468 bioimageio_cli_path ,
446469 )
447470
0 commit comments