示例#1
0
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"]
示例#2
0
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"]
示例#3
0
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"]
示例#4
0
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"]
示例#5
0
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"]
示例#6
0
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"]
示例#7
0
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"]
示例#8
0
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
示例#9
0
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"]
示例#10
0
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"]
示例#11
0
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"]
示例#12
0
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)
示例#13
0
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"]
示例#14
0
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"]
示例#15
0
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"]
示例#16
0
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."]
示例#17
0
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"]
示例#18
0
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"])