Skip to content

Fix uncached downloads #699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 63 commits into from
Jun 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
bc32829
log pyright version
FynnBe Apr 2, 2025
e543fd6
add warning about dangerous typeguards
FynnBe Apr 3, 2025
e0812f2
fix cacheless download to in-memory zip
FynnBe Apr 4, 2025
0925aa7
update changelog
FynnBe Apr 4, 2025
5d048ef
allow access to `config` as dict
FynnBe Apr 7, 2025
a68c206
refactor and test internal download helpers
FynnBe Apr 7, 2025
5ea00be
display summary when exported descr is invalid
FynnBe Apr 8, 2025
d9627e6
exclude content from OpenedBioimageioYaml repr
FynnBe Apr 8, 2025
49731da
keep tmp zipfile open
FynnBe Apr 8, 2025
40e74d2
set root to zip file when opening a zip file
FynnBe Apr 8, 2025
e53dfc6
import optional dependency lxml locally
FynnBe Apr 8, 2025
0899774
run pytest-coverage only in CI
FynnBe Apr 8, 2025
7545cc6
expand user in given cache_path
FynnBe Apr 11, 2025
ecd5c56
WIP update caching
FynnBe Apr 11, 2025
a85661b
WIP overhaul progressbar
FynnBe Apr 11, 2025
e95a6d7
WIP get_package_content
FynnBe Apr 25, 2025
56c3acb
WIP use genericache
FynnBe Apr 30, 2025
c15c2af
improve EnsureDtypeDescr example
FynnBe May 9, 2025
bd044de
add disk cache to settings
FynnBe May 9, 2025
86b7c61
update progressbars
FynnBe May 9, 2025
58385f4
WIP download -> open
FynnBe May 9, 2025
37e1122
add test_progress
FynnBe May 9, 2025
a17450a
open -> get_reader
FynnBe May 21, 2025
06a960a
improve io
FynnBe May 21, 2025
1b36ef1
requests -> httpx
FynnBe May 21, 2025
78cf8dc
bump pydantic
FynnBe May 22, 2025
2ec9de2
pyright and pydantic updates
FynnBe May 22, 2025
df85ea7
avoid type error when creating an error entry
FynnBe Jun 6, 2025
2e366a1
extend test_save_bioimageio_package to include loading from zip
FynnBe Jun 6, 2025
eb2fa73
add force_recompute flag
FynnBe Jun 10, 2025
0e45741
expose BytesReader
FynnBe Jun 10, 2025
b9304fa
add pydantic-version to build matrix
FynnBe Jun 10, 2025
b2c8823
add json_schema_for_humans to dev deps
FynnBe Jun 10, 2025
767a9dd
reset reader pos after computing sha256
FynnBe Jun 10, 2025
3912846
fix wrong pin
FynnBe Jun 10, 2025
709961b
Merge branch 'fixes' into dev
FynnBe Jun 13, 2025
564cbc6
bump pyright
FynnBe Jun 13, 2025
f396ffa
improve is_zipfile check
FynnBe Jun 13, 2025
bec5ba4
fix open_bioimageio_yaml
FynnBe Jun 13, 2025
e23f564
explicitly serialize relative path objects\n\nfixes serializing absol…
FynnBe Jun 17, 2025
95f4d03
remove commented code
FynnBe Jun 17, 2025
a786376
use slots in frozen dataclasses
FynnBe Jun 17, 2025
2927523
fix test_url
FynnBe Jun 17, 2025
e0cc206
enable pretty validation errors in ipython on import
FynnBe Jun 17, 2025
53e75e8
improve use of FileSource and FileDescr
FynnBe Jun 18, 2025
33b73a0
add test_package_file_descr
FynnBe Jun 18, 2025
92216c8
clean up
FynnBe Jun 18, 2025
4d9dc16
apply allow_pickle to load_array
FynnBe Jun 18, 2025
abd73a5
update tests
FynnBe Jun 24, 2025
39bd012
pip install 'compatible release' with '~='
FynnBe Jun 24, 2025
53bd140
bump genericache
FynnBe Jun 24, 2025
eb94d4b
fix package FileDescr
FynnBe Jun 24, 2025
f34bd66
warn (don't fail) on URL errors
FynnBe Jun 24, 2025
4f6eb83
remove redundant validation detail for invalid resources
FynnBe Jun 24, 2025
1400518
add get_pip_deps helper
FynnBe Jun 24, 2025
efbcbec
fix exists method for URLs with warning
FynnBe Jun 24, 2025
0e9a2d7
increase tolerance for mismatched elements per million
FynnBe Jun 25, 2025
d6cd09d
update tests and url validation
FynnBe Jun 25, 2025
0f0d5df
remove AbsoluteFilePath from descr modules
FynnBe Jun 26, 2025
b8ef5eb
update test_specific_reexports_generics
FynnBe Jun 26, 2025
b89bd58
fix pyright
FynnBe Jun 26, 2025
82375e5
fix coverage
FynnBe Jun 26, 2025
7a6a73c
avoid IndexError during suffix validation
FynnBe Jun 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11","3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11","3.12", "3.13"]
pydantic-version: ["2.10.3", "2.11.0"]
include:
- python-version: "3.12"
is-dev-version: true
Expand All @@ -26,7 +27,7 @@ jobs:
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -e .[dev]
pip install pydantic~=${{matrix.pydantic-version }} -e .[dev]
- name: Get Date
id: get-date
run: |
Expand All @@ -41,20 +42,18 @@ jobs:
run: python scripts/generate_version_submodule_imports.py check
- run: black --check .
if: matrix.is-dev-version
- name: install additinal deps for a full pyright check
run: pip install json_schema_for_humans
if: matrix.is-dev-version
- run: ruff check
if: matrix.is-dev-version
- run: pyright --version
- name: Run Pyright
if: matrix.is-dev-version
- run: pyright -p pyproject.toml --pythonversion ${{ matrix.python-version }}
if: matrix.is-dev-version
- run: pytest
run: |
pyright --version
pyright -p pyproject.toml --pythonversion ${{ matrix.python-version }}
- run: pytest --cov bioimageio --cov-report xml --cov-append --capture no
env:
BIOIMAGEIO_CACHE_PATH: bioimageio_cache
RUN_EXPENSIVE_TESTS: ${{ matrix.run-expensive-tests && 'true' || 'false' }}
- run: pytest --cov-append scripts # also test docstrings in scripts for dev-version
- run: pytest --cov bioimageio --cov-report xml --cov-append --capture no scripts # also test docstrings in scripts for dev-version
if: ${{matrix.is-dev-version}}
env:
BIOIMAGEIO_CACHE_PATH: bioimageio_cache
Expand Down Expand Up @@ -110,7 +109,6 @@ jobs:
run: python -m interactive_docs
- name: Generate JSON schemas
run: python scripts/generate_json_schemas.py
- run: pip install json_schema_for_humans
- name: Generate JSON schema documentation
run: python scripts/generate_json_schema_documentation.py
- name: Generate developer docs
Expand Down
8 changes: 4 additions & 4 deletions bioimageio/spec/_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from ._description_impl import DISCOVER, build_description_impl, get_rd_class_impl
from ._internal.common_nodes import InvalidDescr
from ._internal.io import BioimageioYamlContent
from ._internal.io import BioimageioYamlContent, BioimageioYamlContentView
from ._internal.types import FormatVersionPlaceholder
from ._internal.validation_context import get_validation_context
from .application import (
Expand Down Expand Up @@ -151,7 +151,7 @@ def _get_rd_class(typ: Any, format_version: Any):

@overload
def build_description(
content: BioimageioYamlContent,
content: BioimageioYamlContentView,
/,
*,
context: Optional[ValidationContext] = None,
Expand All @@ -161,7 +161,7 @@ def build_description(

@overload
def build_description(
content: BioimageioYamlContent,
content: BioimageioYamlContentView,
/,
*,
context: Optional[ValidationContext] = None,
Expand All @@ -170,7 +170,7 @@ def build_description(


def build_description(
content: BioimageioYamlContent,
content: BioimageioYamlContentView,
/,
*,
context: Optional[ValidationContext] = None,
Expand Down
7 changes: 4 additions & 3 deletions bioimageio/spec/_description_impl.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""implementation details for building a bioimage.io resource description"""

import collections.abc
from typing import Any, Callable, List, Literal, Mapping, Optional, Type, TypeVar, Union

from ._internal.common_nodes import InvalidDescr, ResourceDescrBase
from ._internal.io import BioimageioYamlContent
from ._internal.io import BioimageioYamlContentView
from ._internal.types import FormatVersionPlaceholder
from ._internal.validation_context import ValidationContext, get_validation_context
from .summary import (
Expand Down Expand Up @@ -48,7 +49,7 @@ def get_rd_class_impl(


def build_description_impl(
content: BioimageioYamlContent,
content: BioimageioYamlContentView,
/,
*,
context: Optional[ValidationContext] = None,
Expand All @@ -57,7 +58,7 @@ def build_description_impl(
) -> Union[ResourceDescrT, InvalidDescr]:
context = context or get_validation_context()
errors: List[ErrorEntry] = []
if isinstance(content, dict):
if isinstance(content, collections.abc.Mapping):
for minimum in ("type", "format_version"):
if minimum not in content:
errors.append(
Expand Down
34 changes: 12 additions & 22 deletions bioimageio/spec/_get_conda_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
from typing_extensions import assert_never

from ._internal.gh_utils import set_github_warning
from ._internal.io_utils import ZipPath, read_yaml
from .common import RelativeFilePath
from ._internal.io import FileDescr, get_reader
from ._internal.io_utils import read_yaml
from .conda_env import BioimageioCondaEnv, PipDeps
from .model import v0_4, v0_5
from .model.v0_5 import Version
from .utils import download

SupportedWeightsEntry = Union[
v0_4.KerasHdf5WeightsDescr,
Expand Down Expand Up @@ -202,35 +201,26 @@ def _get_default_tf_env(tensorflow_version: Optional[Version]) -> BioimageioCond


def _get_env_from_deps(
deps: Union[v0_4.Dependencies, v0_5.EnvironmentFileDescr],
deps: Union[v0_4.Dependencies, FileDescr],
) -> BioimageioCondaEnv:
if isinstance(deps, v0_4.Dependencies):
deps_reader = get_reader(deps.file)
if deps.manager == "pip":
pip_deps_str = download(deps.file).path.read_text(encoding="utf-8")
assert isinstance(pip_deps_str, str)
pip_deps_str = deps_reader.read_text()
pip_deps = [d.strip() for d in pip_deps_str.split("\n")]
if "bioimageio.core" not in pip_deps:
pip_deps.append("bioimageio.core")

return BioimageioCondaEnv(
dependencies=[PipDeps(pip=pip_deps)],
)
elif deps.manager not in ("conda", "mamba"):
raise ValueError(f"Dependency manager {deps.manager} not supported")
elif deps.manager in ("conda", "mamba"):
return BioimageioCondaEnv.model_validate(read_yaml(deps_reader))
else:
deps_source = (
deps.file.absolute()
if isinstance(deps.file, RelativeFilePath)
else deps.file
)
if isinstance(deps_source, ZipPath):
local = deps_source
else:
local = download(deps_source).path

return BioimageioCondaEnv.model_validate(read_yaml(local))
elif isinstance(deps, v0_5.EnvironmentFileDescr):
local = download(deps.source).path
return BioimageioCondaEnv.model_validate(read_yaml(local))
raise ValueError(f"Dependency manager {deps.manager} not supported")

elif isinstance(deps, FileDescr):
deps_reader = deps.get_reader()
return BioimageioCondaEnv.model_validate(read_yaml(deps_reader))
else:
assert_never(deps)
37 changes: 29 additions & 8 deletions bioimageio/spec/_internal/_settings.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import os
from functools import cached_property
from pathlib import Path
from typing import Optional, Union

import pooch # pyright: ignore [reportMissingTypeStubs]
from pydantic import Field
from genericache import DiskCache
from genericache.digest import UrlDigest
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing_extensions import Annotated

from .root_url import RootHttpUrl


class Settings(BaseSettings, extra="ignore"):
"""environment variables for bioimageio.spec"""
Expand All @@ -15,11 +21,16 @@ class Settings(BaseSettings, extra="ignore"):
)

allow_pickle: bool = False
"""Sets the `allow_pickle` argument for `numpy.load()`/`numpy.save()`"""
"""Sets the `allow_pickle` argument for `numpy.load()`"""

cache_path: Path = pooch.os_cache("bioimageio")
"""bioimageio cache location"""

@field_validator("cache_path", mode="after")
@classmethod
def _expand_user(cls, value: Path):
return Path(os.path.expanduser(str(value)))

collection_http_pattern: str = (
"https://hypha.aicell.io/bioimage-io/artifacts/{bioimageio_id}/files/rdf.yaml"
)
Expand All @@ -41,20 +52,21 @@ class Settings(BaseSettings, extra="ignore"):
)
"""URL to bioimageio id_map_draft.json to resolve draft IDs ending with '/draft'."""

perform_io_checks: bool = True
"""Wether or not to perform validation that requires file io,
e.g. downloading a remote files.

Existence of any local absolute file paths is still being checked."""

resolve_draft: bool = True
"""Flag to resolve draft resource versions following the pattern
<resource id>/draft.

Note that anyone may stage a new draft and that such a draft version
may not have been reviewed yet.
Set this flag to False to avoid this potential security risk
and disallow loading draft versions."""

perform_io_checks: bool = True
"""Wether or not to perform validation that requires file io,
e.g. downloading a remote files.

Existence of any local absolute file paths is still being checked."""

log_warnings: bool = True
"""Log validation warnings to console."""

Expand All @@ -77,6 +89,15 @@ def github_auth(self):
else:
return (self.github_username, self.github_token)

@cached_property
def disk_cache(self):
cache = DiskCache[RootHttpUrl].create(
url_type=RootHttpUrl,
cache_dir=self.cache_path,
url_hasher=UrlDigest.from_str,
)
return cache


settings = Settings()
"""parsed environment variables for bioimageio.spec"""
Loading
Loading