def test_validate_model_as_string(unet2d_nuclei_broad_latest_path): from bioimageio.spec.commands import validate data = unet2d_nuclei_broad_latest_path.read_text() assert not validate(data, update_format=True, update_format_inner=False)["error"] assert not validate(data, update_format=False, update_format_inner=False)["error"]
def test_validate_invalid_model(unet2d_nuclei_broad_latest): from bioimageio.spec.commands import validate data = copy(unet2d_nuclei_broad_latest) del data["test_inputs"] # invalidate data assert validate(data, update_format=True, update_format_inner=False)["error"] assert validate(data, update_format=False, update_format_inner=False)["error"]
def test_validate_invalid(unet2d_nuclei_broad_collection): from bioimageio.spec.commands import validate data = copy(unet2d_nuclei_broad_collection) data["collection"][0]["name"] = 1 # invalidate data assert validate(data, update_format=True, update_format_inner=False)["error"] assert validate(data, update_format=False, update_format_inner=False)["error"]
def test_validate(unet2d_nuclei_broad_collection): from bioimageio.spec.commands import validate assert not validate(unet2d_nuclei_broad_collection, update_format=True, update_format_inner=False)["error"] assert not validate(unet2d_nuclei_broad_collection, update_format=False, update_format_inner=False)["error"]
def test_validate_model_as_dict(unet2d_nuclei_broad_any): from bioimageio.spec.commands import validate assert not validate(unet2d_nuclei_broad_any, update_format=True, update_format_inner=False)["error"] assert not validate(unet2d_nuclei_broad_any, update_format=False, update_format_inner=False)["error"]
def test_validate_model_as_zenodo_doi(): from bioimageio.spec.commands import validate doi = "10.5281/zenodo.5744490" assert not validate(doi, update_format=False, update_format_inner=False)["error"] # expecting UnconvertibleError due to missing sha256 assert validate(doi, update_format=True, update_format_inner=False)["error"]
def test_validate_model_as_bytes_io(unet2d_nuclei_broad_latest_path): from bioimageio.spec.commands import validate data = BytesIO(unet2d_nuclei_broad_latest_path.read_bytes()) data.seek(0) assert not validate(data, update_format=True, update_format_inner=False)["error"] data.seek(0) assert not validate(data, update_format=False, update_format_inner=False)["error"]
def test_validate_dataset(dataset_rdf): from bioimageio.spec.commands import validate summary = validate(dataset_rdf, update_format=True, update_format_inner=False) assert summary["status"] == "passed", summary summary = validate(dataset_rdf, update_format=False, update_format_inner=False) assert summary["status"] == "passed", summary
def test_validate_model_package_on_disk(unet2d_nuclei_broad_latest_path, tmpdir): from bioimageio.spec.commands import validate zf_path = tmpdir / "package.zip" with zipfile.ZipFile(zf_path, "w") as zf: zf.write(unet2d_nuclei_broad_latest_path, "rdf.yaml") assert not validate(zf_path, update_format=True, update_format_inner=False)["error"] assert not validate( zf_path, update_format=False, update_format_inner=False)["error"]
def test_validate_model_as_url(): from bioimageio.spec.commands import validate assert not validate( "https://raw.githubusercontent.com/bioimage-io/spec-bioimage-io/main/example_specs/models/unet2d_nuclei_broad/rdf.yaml", update_format=True, update_format_inner=False, )["error"] assert not validate( "https://raw.githubusercontent.com/bioimage-io/spec-bioimage-io/main/example_specs/models/unet2d_nuclei_broad/rdf.yaml", update_format=False, update_format_inner=False, )["error"]
def test_validate_model_package_as_bytes(unet2d_nuclei_broad_latest_path): from bioimageio.spec.commands import validate data = BytesIO() with zipfile.ZipFile(data, "w") as zf: zf.write(unet2d_nuclei_broad_latest_path, "rdf.yaml") data.seek(0) assert not validate(data, update_format=True, update_format_inner=False)["error"] data.seek(0) assert not validate(data, update_format=False, update_format_inner=False)["error"]
def validate( rdf_source: str = typer.Argument( ..., help="RDF source as relative file path or URI"), update_format: bool = typer.Option( False, help= "Update format version to the latest (might fail even if source adheres to an old format version). " "To inform the format update the source may specify fields of future versions in " "config:future:<future version>.", # todo: add future documentation ), update_format_inner: bool = typer.Option( None, help="For collection RDFs only. Defaults to value of 'update-format'." ), verbose: bool = typer.Option( False, help="show traceback of unexpected (no ValidationError) exceptions"), ): summary = commands.validate(rdf_source, update_format, update_format_inner) if summary["error"] is not None: print(f"Error in {summary['name']}:") pprint(summary["error"]) if verbose: print("traceback:") pprint(summary["traceback"]) ret_code = 1 else: print(f"No validation errors for {summary['name']}") ret_code = 0 if summary["warnings"]: print(f"Validation Warnings for {summary['name']}:") pprint(summary["warnings"]) sys.exit(ret_code)
def test_validate_model_as_bioimageio_resource_id_zenodo(): from bioimageio.spec.commands import validate resource_id = "10.5281/zenodo.5874741" summary = validate(resource_id, update_format=False, update_format_inner=False) assert summary["status"] == "passed", summary["error"]
def test_validate_model_as_bioimageio_resource_id_partner(): from bioimageio.spec.commands import validate resource_id = "ilastik/isbi2012_neuron_segmentation_challenge" summary = validate(resource_id, update_format=False, update_format_inner=False) assert summary["status"] == "passed", summary["error"]
def test_validate_generates_warnings(unet2d_nuclei_broad_latest): from bioimageio.spec.commands import validate data = copy(unet2d_nuclei_broad_latest) data["license"] = "BSD-2-Clause-FreeBSD" data["run_mode"] = {"name": "fancy"} summary = validate(data, update_format=True, update_format_inner=False) assert summary["warnings"]
def test_list_instead_of_nested_schema(unet2d_nuclei_broad_latest): from bioimageio.spec.commands import validate data = unet2d_nuclei_broad_latest # set wrong run_mode (list) data["run_mode"] = [{"name": "something"}] error = validate(data)["error"] print(error) assert len(error) == 1 assert error["run_mode"] == ["Expected dictionary, but got list."]
def test_validate_model_as_zenodo_sandbox_doi(): from bioimageio.spec.commands import validate doi = "10.5281/zenodo.5744489" assert not validate(doi, update_format=False, update_format_inner=False)["error"]
def parse_manifest(models_yaml): collection_tags = [] if models_yaml.get("config"): cfg = models_yaml.get("config") if cfg.get("tags"): tags = cfg.get("tags") if isinstance(tags, list): collection_tags = cfg.get("tags") if "collection" in models_yaml: for item in models_yaml["collection"]: print("Loading collection from " + item["source"]) response = requests.get(item["source"]) if response.status_code != 200: print("Failed to fetch collection manifest from " + item["id"]) continue collection_yaml = yaml.safe_load(response.content) collection_yaml["parent_collection"] = item["source"] if "config" in collection_yaml: collections.append(collection_yaml["config"]) try: parse_manifest(collection_yaml) except Exception as e: print("Failed to parse manifest " + str(item.get("source"))) print(traceback.format_exc()) if "application" in models_yaml: for item in models_yaml["application"]: app_url = item.get("source") if app_url and app_url.endswith(".imjoy.html"): if os.path.exists(app_url): content = open(app_url, "r").read() if not app_url.startswith("http"): app_url = item["source"].strip("/").strip("./") app_url = models_yaml["config"]["url_root"].strip("/") + "/" + app_url else: if not app_url.startswith("http"): app_url = item["source"].strip("/").strip("./") app_url = models_yaml["config"]["url_root"].strip("/") + "/" + app_url response = requests.get(app_url) if response.status_code != 200: print("Failed to fetch model config from " + app_url) continue content = response.content.decode("utf-8") found = re.findall("<config (.*)>(.*)</config>", content, re.DOTALL)[0] if "json" in found[0]: plugin_config = json.loads(found[1]) elif "yaml" in found[0]: plugin_config = yaml.safe_load(found[1]) else: raise Exception("config not found in " + app_url) app_config = { "id": item["id"], "type": "application", "source": app_url, "passive": item.get("passive", False), } fields = [ "icon", "name", "version", "api_version", "description", "license", "requirements", "dependencies", "env", "passive", ] for f in fields: if f in plugin_config: app_config[f] = plugin_config[f] tags = plugin_config.get("labels", []) + plugin_config.get("flags", []) if "bioengine" not in tags: tags.append("bioengine") app_config["tags"] = tags app_config["documentation"] = plugin_config.get("docs") app_config["covers"] = plugin_config.get("cover") # make sure we have a list if not app_config["covers"]: app_config["covers"] = [] elif type(app_config["covers"]) is not list: app_config["covers"] = [app_config["covers"]] app_config["badges"] = plugin_config.get("badge") if not app_config["badges"]: app_config["badges"] = [] elif type(app_config["badges"]) is not list: app_config["badges"] = [app_config["badges"]] app_config["authors"] = plugin_config.get("author") if not app_config["authors"]: app_config["authors"] = [] elif type(app_config["authors"]) is not list: app_config["authors"] = [app_config["authors"]] assert item["id"] == plugin_config["name"], ( "Please use the app name (" + plugin_config["name"] + ") as its application id." ) else: item["type"] = "application" app_config = item if "id" not in app_config: app_config["id"] = app_config["name"].replace(" ", "-") app_config["id"] = models_yaml["config"]["id"] + "/" + app_config["id"] if "links" in app_config: for i in range(len(app_config["links"])): if "/" not in app_config["links"][i]: app_config["links"][i] = models_yaml["config"]["id"] + "/" + app_config["links"][i] compiled_apps.append(app_config) print("Added application: " + app_config["name"]) for tp in ["model", "dataset", "notebook", "workflow"]: if tp not in models_yaml: continue for item in models_yaml[tp]: model_info = {"type": tp, "attachments": {}} if "source" in item and (item["source"].endswith("yaml") or item["source"].endswith("yml")): source = item["source"] try: if source.startswith("http"): response = requests.get(source) if response.status_code != 200: print("Failed to fetch source from " + source) continue if source.endswith(".yaml") or source.endswith(".yml"): model_config = yaml.safe_load(response.content) root_url = "/".join(source.split("/")[:-1]) else: with open(source, "rb") as fil: model_config = yaml.safe_load(fil) item["source"] = models_yaml["config"]["url_root"].strip("/") + "/" + source root_url = models_yaml["config"]["url_root"].strip("/") + "/" + "/".join(source.split("/")[:-1]) # merge item from models.yaml to model config item.update(model_config) if tp == "model": if "error" not in item: item["error"] = {} try: validate(source, verbose=True) except ValidationError as e: print(f'Error when verifying {item["id"]}: {e.messages}') item["error"] = {"spec": e.messages} except Exception as e: print(f'Failed to verify the model: {item["id"]}: {e}') item["error"] = {"spec": f"Failed to verify the model: {e}"} except: print("Failed to download or parse source file from " + source) raise model_info["source"] = source else: root_url = None if root_url is not None: model_info["root_url"] = root_url attachments = model_info["attachments"] if "files" in item: attachments["files"] = item["files"] if "weights" in item: attachments["weights"] = item["weights"] for k in item: # normalize relative path if k in ["documentation"]: if item[k]: item[k] = item[k].strip("/").strip("./") if k == "covers": if isinstance(item[k], list): for j in range(len(item[k])): item[k][j] = item[k][j].strip("/").strip("./") if k in preserved_keys: # don't copy model source model_info[k] = item[k] if "source" not in model_info and "source" in item: model_info["source"] = item["source"] if len(model_info["attachments"]) <= 0: del model_info["attachments"] if "tags" in model_info: model_info["tags"] += collection_tags else: model_info["tags"] = collection_tags if "id" not in model_info: model_info["id"] = model_info["name"].replace(" ", "-") model_info["id"] = models_yaml["config"]["id"] + "/" + model_info["id"] if "links" in model_info: for i in range(len(model_info["links"])): if "/" not in model_info["links"][i]: model_info["links"][i] = models_yaml["config"]["id"] + "/" + model_info["links"][i] compiled_items.append(model_info) print("Added " + model_info["type"] + ": " + model_info["name"])