From 37d2cd7c401da4b44a28b2c8f722ce523047f483 Mon Sep 17 00:00:00 2001 From: drbh Date: Thu, 19 Feb 2026 13:09:03 -0500 Subject: [PATCH 1/4] feat: support redirection --- kernels/src/kernels/cli/__init__.py | 7 ++- kernels/src/kernels/lockfile.py | 8 ++- kernels/src/kernels/redirect.py | 56 +++++++++++++++++++ kernels/src/kernels/utils.py | 14 +++-- kernels/tests/test_redirect.py | 84 +++++++++++++++++++++++++++++ 5 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 kernels/src/kernels/redirect.py create mode 100644 kernels/tests/test_redirect.py diff --git a/kernels/src/kernels/cli/__init__.py b/kernels/src/kernels/cli/__init__.py index 8d84df48..36ce1b2b 100644 --- a/kernels/src/kernels/cli/__init__.py +++ b/kernels/src/kernels/cli/__init__.py @@ -297,12 +297,14 @@ def download_kernels(args): for kernel_lock_json in lock_json: kernel_lock = KernelLock.from_json(kernel_lock_json) print( - f"Downloading `{kernel_lock.repo_id}` at with SHA: {kernel_lock.sha}", + f"Downloading `{kernel_lock.repo_id}` with SHA: {kernel_lock.sha}", file=sys.stderr, ) if args.all_variants: install_kernel_all_variants( - kernel_lock.repo_id, kernel_lock.sha, variant_locks=kernel_lock.variants + kernel_lock.repo_id, + kernel_lock.sha, + variant_locks=kernel_lock.variants, ) else: try: @@ -331,6 +333,7 @@ def lock_kernels(args): all_locks = [] for kernel, version in kernel_versions.items(): + print(f"Locking `{kernel}` at version {version}", file=sys.stderr) all_locks.append(get_kernel_locks(kernel, version)) with open(args.project_dir / "kernels.lock", "w") as f: diff --git a/kernels/src/kernels/lockfile.py b/kernels/src/kernels/lockfile.py index 58cf78b3..250e233f 100644 --- a/kernels/src/kernels/lockfile.py +++ b/kernels/src/kernels/lockfile.py @@ -4,6 +4,7 @@ from kernels._versions import resolve_version_spec_as_ref from kernels.compat import tomllib +from kernels.redirect import resolve_redirect @dataclass @@ -35,9 +36,14 @@ def get_kernel_locks(repo_id: str, version_spec: int | str) -> KernelLock: """ from kernels.utils import _get_hf_api + api = _get_hf_api() + + # Check for redirects before resolving version + repo_id, _ = resolve_redirect(api, repo_id, "main") + tag_for_newest = resolve_version_spec_as_ref(repo_id, version_spec) - r = _get_hf_api().repo_info( + r = api.repo_info( repo_id=repo_id, revision=tag_for_newest.target_commit, files_metadata=True ) if r.sha is None: diff --git a/kernels/src/kernels/redirect.py b/kernels/src/kernels/redirect.py new file mode 100644 index 00000000..5a2519bb --- /dev/null +++ b/kernels/src/kernels/redirect.py @@ -0,0 +1,56 @@ +import logging +import warnings +from dataclasses import dataclass + +from huggingface_hub import HfApi +from huggingface_hub.utils import EntryNotFoundError + +from kernels.compat import tomllib + +REDIRECT_FILENAME = "REDIRECT.toml" + + +@dataclass +class RedirectInfo: + destination: str + message: str + + +def parse_redirect_file(content: str) -> RedirectInfo: + data = tomllib.loads(content) + destination = data.get("destination") + if not destination: + raise ValueError("REDIRECT.toml must contain a 'destination' field") + return RedirectInfo(destination=destination, message=data.get("message", "")) + + +# Check for a redirect file in the repository +def _check_redirect(api: HfApi, repo_id: str, revision: str) -> RedirectInfo | None: + try: + path = api.hf_hub_download( + repo_id=repo_id, filename=REDIRECT_FILENAME, revision=revision + ) + with open(path, "r") as f: + return parse_redirect_file(f.read()) + except EntryNotFoundError: + return None + + +def resolve_redirect(api: HfApi, repo_id: str, revision: str) -> tuple[str, str]: + redirect = _check_redirect(api, repo_id, revision) + if redirect is None: + return repo_id, revision + + msg = f"WARNING: '{repo_id}' redirected to '{redirect.destination}'" + if redirect.message: + msg = f"WARNING: {redirect.message}" + + RED_COLOR = "\033[91m" + RESET_COLOR = "\033[0m" + msg = f"\n{RED_COLOR}{msg}{RESET_COLOR}" + + warnings.warn(msg, UserWarning) + + if "@" in redirect.destination: + return redirect.destination.rsplit("@", 1) + return redirect.destination, "main" diff --git a/kernels/src/kernels/utils.py b/kernels/src/kernels/utils.py index 7ee546f1..c9a83882 100644 --- a/kernels/src/kernels/utils.py +++ b/kernels/src/kernels/utils.py @@ -21,6 +21,7 @@ from kernels.deps import validate_dependencies from kernels.lockfile import KernelLock, VariantLock from kernels.metadata import Metadata +from kernels.redirect import resolve_redirect KNOWN_BACKENDS = {"cpu", "cuda", "metal", "rocm", "xpu", "npu"} @@ -207,6 +208,7 @@ def install_kernel( backend: str | None = None, variant_locks: dict[str, VariantLock] | None = None, user_agent: str | dict | None = None, + follow_redirects: bool = True, ) -> tuple[str, Path]: """ Download a kernel for the current environment to the cache. @@ -227,13 +229,20 @@ def install_kernel( Optional dictionary of variant locks for validation. user_agent (`Union[str, dict]`, *optional*): The `user_agent` info to pass to `snapshot_download()` for internal telemetry. + follow_redirects (`bool`, *optional*, defaults to `True`): + Whether to follow REDIRECT files to the new repository location. Returns: `tuple[str, Path]`: A tuple containing the package name and the path to the variant directory. """ + api = _get_hf_api(user_agent=user_agent) + + # Check for redirects + if follow_redirects and not local_files_only: + repo_id, revision = resolve_redirect(api, repo_id, revision) + package_name = package_name_from_repo_id(repo_id) allow_patterns = [f"build/{variant}/*" for variant in _build_variants(backend)] - api = _get_hf_api(user_agent=user_agent) repo_path = Path( str( api.snapshot_download( @@ -443,10 +452,9 @@ def has_kernel( `bool`: `True` if a kernel is available for the current environment. """ revision = select_revision_or_version(repo_id, revision=revision, version=version) - + api = _get_hf_api() package_name = package_name_from_repo_id(repo_id) - api = _get_hf_api() for variant in _build_variants(backend): for init_file in ["__init__.py", f"{package_name}/__init__.py"]: if api.file_exists( diff --git a/kernels/tests/test_redirect.py b/kernels/tests/test_redirect.py new file mode 100644 index 00000000..1dc33564 --- /dev/null +++ b/kernels/tests/test_redirect.py @@ -0,0 +1,84 @@ +import pytest +from unittest.mock import MagicMock + +from kernels.redirect import ( + RedirectInfo, + parse_redirect_file, + resolve_redirect, +) + + +class TestParseRedirectFile: + def test_simple_redirect(self): + content = 'destination = "kernels-community/new-kernel"' + result = parse_redirect_file(content) + assert result.destination == "kernels-community/new-kernel" + assert result.message == "" + + def test_redirect_with_message(self): + content = '''destination = "kernels-community/new-kernel" +message = "This kernel has been moved to a new location."''' + result = parse_redirect_file(content) + assert result.destination == "kernels-community/new-kernel" + assert "moved to a new location" in result.message + + def test_redirect_with_revision(self): + content = 'destination = "kernels-community/new-kernel@v2"' + result = parse_redirect_file(content) + assert result.destination == "kernels-community/new-kernel@v2" + + def test_missing_destination_raises(self): + with pytest.raises(ValueError, match="must contain a 'destination'"): + parse_redirect_file('message = "no destination"') + + def test_empty_content_raises(self): + with pytest.raises(ValueError, match="must contain a 'destination'"): + parse_redirect_file("") + + +class TestResolveRedirect: + def test_no_redirect(self): + from huggingface_hub.utils import EntryNotFoundError + + mock_api = MagicMock() + mock_api.hf_hub_download.side_effect = EntryNotFoundError("Not found") + + repo_id, revision = resolve_redirect(mock_api, "kernels-test/kernel", "main") + assert repo_id == "kernels-test/kernel" + assert revision == "main" + + def test_single_redirect(self, tmp_path): + from huggingface_hub.utils import EntryNotFoundError + + redirect_file = tmp_path / "REDIRECT.toml" + redirect_file.write_text('destination = "kernels-community/new-kernel"\nmessage = "Kernel moved"') + + def mock_download(repo_id, filename, revision): + if repo_id == "kernels-test/old-kernel": + return str(redirect_file) + raise EntryNotFoundError("Not found") + + mock_api = MagicMock() + mock_api.hf_hub_download.side_effect = mock_download + + repo_id, revision = resolve_redirect(mock_api, "kernels-test/old-kernel", "main") + assert repo_id == "kernels-community/new-kernel" + assert revision == "main" + + def test_redirect_with_revision(self, tmp_path): + from huggingface_hub.utils import EntryNotFoundError + + redirect_file = tmp_path / "REDIRECT.toml" + redirect_file.write_text('destination = "kernels-community/new-kernel@v2"') + + def mock_download(repo_id, filename, revision): + if repo_id == "kernels-test/old-kernel": + return str(redirect_file) + raise EntryNotFoundError("Not found") + + mock_api = MagicMock() + mock_api.hf_hub_download.side_effect = mock_download + + repo_id, revision = resolve_redirect(mock_api, "kernels-test/old-kernel", "main") + assert repo_id == "kernels-community/new-kernel" + assert revision == "v2" From 84f76de61013e3ae351ee522d295486eba07dedd Mon Sep 17 00:00:00 2001 From: drbh Date: Wed, 25 Feb 2026 11:42:31 -0500 Subject: [PATCH 2/4] fix: prefer status --- kernels/src/kernels/lockfile.py | 8 +-- kernels/src/kernels/redirect.py | 56 -------------------- kernels/src/kernels/status.py | 77 +++++++++++++++++++++++++++ kernels/src/kernels/utils.py | 10 ++-- kernels/tests/test_redirect.py | 84 ----------------------------- kernels/tests/test_status.py | 93 +++++++++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 150 deletions(-) delete mode 100644 kernels/src/kernels/redirect.py create mode 100644 kernels/src/kernels/status.py delete mode 100644 kernels/tests/test_redirect.py create mode 100644 kernels/tests/test_status.py diff --git a/kernels/src/kernels/lockfile.py b/kernels/src/kernels/lockfile.py index 250e233f..2aca2eef 100644 --- a/kernels/src/kernels/lockfile.py +++ b/kernels/src/kernels/lockfile.py @@ -4,7 +4,7 @@ from kernels._versions import resolve_version_spec_as_ref from kernels.compat import tomllib -from kernels.redirect import resolve_redirect +from kernels.status import resolve_status @dataclass @@ -38,8 +38,10 @@ def get_kernel_locks(repo_id: str, version_spec: int | str) -> KernelLock: api = _get_hf_api() - # Check for redirects before resolving version - repo_id, _ = resolve_redirect(api, repo_id, "main") + # NOTE: the destination of a redirect is respected but we still use + # resolve_version_spec_as_ref to resolve the version specifier of the + # final destination repo. + repo_id, _ = resolve_status(api, repo_id, "main") tag_for_newest = resolve_version_spec_as_ref(repo_id, version_spec) diff --git a/kernels/src/kernels/redirect.py b/kernels/src/kernels/redirect.py deleted file mode 100644 index 5a2519bb..00000000 --- a/kernels/src/kernels/redirect.py +++ /dev/null @@ -1,56 +0,0 @@ -import logging -import warnings -from dataclasses import dataclass - -from huggingface_hub import HfApi -from huggingface_hub.utils import EntryNotFoundError - -from kernels.compat import tomllib - -REDIRECT_FILENAME = "REDIRECT.toml" - - -@dataclass -class RedirectInfo: - destination: str - message: str - - -def parse_redirect_file(content: str) -> RedirectInfo: - data = tomllib.loads(content) - destination = data.get("destination") - if not destination: - raise ValueError("REDIRECT.toml must contain a 'destination' field") - return RedirectInfo(destination=destination, message=data.get("message", "")) - - -# Check for a redirect file in the repository -def _check_redirect(api: HfApi, repo_id: str, revision: str) -> RedirectInfo | None: - try: - path = api.hf_hub_download( - repo_id=repo_id, filename=REDIRECT_FILENAME, revision=revision - ) - with open(path, "r") as f: - return parse_redirect_file(f.read()) - except EntryNotFoundError: - return None - - -def resolve_redirect(api: HfApi, repo_id: str, revision: str) -> tuple[str, str]: - redirect = _check_redirect(api, repo_id, revision) - if redirect is None: - return repo_id, revision - - msg = f"WARNING: '{repo_id}' redirected to '{redirect.destination}'" - if redirect.message: - msg = f"WARNING: {redirect.message}" - - RED_COLOR = "\033[91m" - RESET_COLOR = "\033[0m" - msg = f"\n{RED_COLOR}{msg}{RESET_COLOR}" - - warnings.warn(msg, UserWarning) - - if "@" in redirect.destination: - return redirect.destination.rsplit("@", 1) - return redirect.destination, "main" diff --git a/kernels/src/kernels/status.py b/kernels/src/kernels/status.py new file mode 100644 index 00000000..9cb82a7f --- /dev/null +++ b/kernels/src/kernels/status.py @@ -0,0 +1,77 @@ +import warnings +from dataclasses import dataclass +from typing import Union + +from huggingface_hub import HfApi +from huggingface_hub.utils import EntryNotFoundError + +from kernels.compat import tomllib + + +@dataclass +class Redirect: + kind: str # must be "redirect" + destination: str + revision: str + + @staticmethod + def from_dict(data: dict) -> "Redirect": + if data.get("kind") != "redirect": + raise ValueError("kernel-status.toml kind must be 'redirect' for Redirect") + destination = data.get("destination") + if not destination: + raise ValueError("kernel-status.toml must contain a 'destination' field") + return Redirect( + kind="redirect", + destination=destination, + revision=data.get("revision", "main"), + ) + + +KernelStatusKind = Union[Redirect] + + +@dataclass +class KernelStatus: + + def from_toml(content: str) -> KernelStatusKind: + data = tomllib.loads(content) + + kind = data.get("kind") + if not kind: + raise ValueError("kernel-status.toml must contain a 'kind' field") + + if kind == "redirect": + return Redirect.from_dict(data) + + raise ValueError(f"Unknown kernel status kind: {kind!r}") + + # Fetch the kernel status from the repository, if it exists + def check_status( + api: HfApi, repo_id: str, revision: str + ) -> KernelStatusKind | None: + try: + path = api.hf_hub_download( + repo_id=repo_id, filename="kernel-status.toml", revision=revision + ) + with open(path, "r") as f: + return KernelStatus.from_toml(f.read()) + except EntryNotFoundError: + return None + + +def resolve_status(api: HfApi, repo_id: str, revision: str) -> tuple[str, str]: + status = KernelStatus.check_status(api, repo_id, revision) + if status is None: + return repo_id, revision + + # In the case of a redirect, return the destination repo and revision + if isinstance(status, Redirect): + warnings.warn( + f"'{repo_id}' redirected to '{status.destination}'", + UserWarning, + stacklevel=2, + ) + return status.destination, status.revision + + return repo_id, revision diff --git a/kernels/src/kernels/utils.py b/kernels/src/kernels/utils.py index c9a83882..dc96d2ad 100644 --- a/kernels/src/kernels/utils.py +++ b/kernels/src/kernels/utils.py @@ -21,7 +21,7 @@ from kernels.deps import validate_dependencies from kernels.lockfile import KernelLock, VariantLock from kernels.metadata import Metadata -from kernels.redirect import resolve_redirect +from kernels.status import resolve_status KNOWN_BACKENDS = {"cpu", "cuda", "metal", "rocm", "xpu", "npu"} @@ -208,7 +208,6 @@ def install_kernel( backend: str | None = None, variant_locks: dict[str, VariantLock] | None = None, user_agent: str | dict | None = None, - follow_redirects: bool = True, ) -> tuple[str, Path]: """ Download a kernel for the current environment to the cache. @@ -229,17 +228,14 @@ def install_kernel( Optional dictionary of variant locks for validation. user_agent (`Union[str, dict]`, *optional*): The `user_agent` info to pass to `snapshot_download()` for internal telemetry. - follow_redirects (`bool`, *optional*, defaults to `True`): - Whether to follow REDIRECT files to the new repository location. Returns: `tuple[str, Path]`: A tuple containing the package name and the path to the variant directory. """ api = _get_hf_api(user_agent=user_agent) - # Check for redirects - if follow_redirects and not local_files_only: - repo_id, revision = resolve_redirect(api, repo_id, revision) + if not local_files_only: + repo_id, revision = resolve_status(api, repo_id, revision) package_name = package_name_from_repo_id(repo_id) allow_patterns = [f"build/{variant}/*" for variant in _build_variants(backend)] diff --git a/kernels/tests/test_redirect.py b/kernels/tests/test_redirect.py deleted file mode 100644 index 1dc33564..00000000 --- a/kernels/tests/test_redirect.py +++ /dev/null @@ -1,84 +0,0 @@ -import pytest -from unittest.mock import MagicMock - -from kernels.redirect import ( - RedirectInfo, - parse_redirect_file, - resolve_redirect, -) - - -class TestParseRedirectFile: - def test_simple_redirect(self): - content = 'destination = "kernels-community/new-kernel"' - result = parse_redirect_file(content) - assert result.destination == "kernels-community/new-kernel" - assert result.message == "" - - def test_redirect_with_message(self): - content = '''destination = "kernels-community/new-kernel" -message = "This kernel has been moved to a new location."''' - result = parse_redirect_file(content) - assert result.destination == "kernels-community/new-kernel" - assert "moved to a new location" in result.message - - def test_redirect_with_revision(self): - content = 'destination = "kernels-community/new-kernel@v2"' - result = parse_redirect_file(content) - assert result.destination == "kernels-community/new-kernel@v2" - - def test_missing_destination_raises(self): - with pytest.raises(ValueError, match="must contain a 'destination'"): - parse_redirect_file('message = "no destination"') - - def test_empty_content_raises(self): - with pytest.raises(ValueError, match="must contain a 'destination'"): - parse_redirect_file("") - - -class TestResolveRedirect: - def test_no_redirect(self): - from huggingface_hub.utils import EntryNotFoundError - - mock_api = MagicMock() - mock_api.hf_hub_download.side_effect = EntryNotFoundError("Not found") - - repo_id, revision = resolve_redirect(mock_api, "kernels-test/kernel", "main") - assert repo_id == "kernels-test/kernel" - assert revision == "main" - - def test_single_redirect(self, tmp_path): - from huggingface_hub.utils import EntryNotFoundError - - redirect_file = tmp_path / "REDIRECT.toml" - redirect_file.write_text('destination = "kernels-community/new-kernel"\nmessage = "Kernel moved"') - - def mock_download(repo_id, filename, revision): - if repo_id == "kernels-test/old-kernel": - return str(redirect_file) - raise EntryNotFoundError("Not found") - - mock_api = MagicMock() - mock_api.hf_hub_download.side_effect = mock_download - - repo_id, revision = resolve_redirect(mock_api, "kernels-test/old-kernel", "main") - assert repo_id == "kernels-community/new-kernel" - assert revision == "main" - - def test_redirect_with_revision(self, tmp_path): - from huggingface_hub.utils import EntryNotFoundError - - redirect_file = tmp_path / "REDIRECT.toml" - redirect_file.write_text('destination = "kernels-community/new-kernel@v2"') - - def mock_download(repo_id, filename, revision): - if repo_id == "kernels-test/old-kernel": - return str(redirect_file) - raise EntryNotFoundError("Not found") - - mock_api = MagicMock() - mock_api.hf_hub_download.side_effect = mock_download - - repo_id, revision = resolve_redirect(mock_api, "kernels-test/old-kernel", "main") - assert repo_id == "kernels-community/new-kernel" - assert revision == "v2" diff --git a/kernels/tests/test_status.py b/kernels/tests/test_status.py new file mode 100644 index 00000000..d9d5bd2b --- /dev/null +++ b/kernels/tests/test_status.py @@ -0,0 +1,93 @@ +import pytest +from unittest.mock import MagicMock + +from kernels.status import ( + Redirect, + KernelStatus, + resolve_status, +) + + +class TestKernelStatusFromToml: + def test_simple_redirect(self): + content = '''kind = "redirect" +destination = "kernels-community/new-kernel"''' + result = KernelStatus.from_toml(content) + assert isinstance(result, Redirect) + assert result.destination == "kernels-community/new-kernel" + assert result.revision == "main" + + def test_redirect_with_revision(self): + content = '''kind = "redirect" +destination = "kernels-community/new-kernel" +revision = "v2"''' + result = KernelStatus.from_toml(content) + assert isinstance(result, Redirect) + assert result.destination == "kernels-community/new-kernel" + assert result.revision == "v2" + + def test_missing_kind_raises(self): + with pytest.raises(ValueError, match="must contain a 'kind' field"): + KernelStatus.from_toml('destination = "kernels-community/new-kernel"') + + def test_unknown_kind_raises(self): + content = '''kind = "unknown" +destination = "kernels-community/new-kernel"''' + with pytest.raises(ValueError, match="Unknown kernel status kind"): + KernelStatus.from_toml(content) + + def test_missing_destination_raises(self): + with pytest.raises(ValueError, match="must contain a 'destination'"): + KernelStatus.from_toml('kind = "redirect"') + + def test_empty_content_raises(self): + with pytest.raises(ValueError, match="must contain a 'kind'"): + KernelStatus.from_toml("") + + +class TestResolveStatus: + def test_no_status(self): + from huggingface_hub.utils import EntryNotFoundError + + mock_api = MagicMock() + mock_api.hf_hub_download.side_effect = EntryNotFoundError("Not found") + + repo_id, revision = resolve_status(mock_api, "kernels-test/kernel", "main") + assert repo_id == "kernels-test/kernel" + assert revision == "main" + + def test_redirect(self, tmp_path): + from huggingface_hub.utils import EntryNotFoundError + + status_file = tmp_path / "kernel-status.toml" + status_file.write_text('kind = "redirect"\ndestination = "kernels-community/new-kernel"') + + def mock_download(repo_id, filename, revision): + if repo_id == "kernels-test/old-kernel": + return str(status_file) + raise EntryNotFoundError("Not found") + + mock_api = MagicMock() + mock_api.hf_hub_download.side_effect = mock_download + + repo_id, revision = resolve_status(mock_api, "kernels-test/old-kernel", "main") + assert repo_id == "kernels-community/new-kernel" + assert revision == "main" + + def test_redirect_with_revision(self, tmp_path): + from huggingface_hub.utils import EntryNotFoundError + + status_file = tmp_path / "kernel-status.toml" + status_file.write_text('kind = "redirect"\ndestination = "kernels-community/new-kernel"\nrevision = "v2"') + + def mock_download(repo_id, filename, revision): + if repo_id == "kernels-test/old-kernel": + return str(status_file) + raise EntryNotFoundError("Not found") + + mock_api = MagicMock() + mock_api.hf_hub_download.side_effect = mock_download + + repo_id, revision = resolve_status(mock_api, "kernels-test/old-kernel", "main") + assert repo_id == "kernels-community/new-kernel" + assert revision == "v2" From dbc65a944f562f4f87afaa3edf0441ece8ac8599 Mon Sep 17 00:00:00 2001 From: drbh Date: Wed, 25 Feb 2026 12:07:25 -0500 Subject: [PATCH 3/4] fix: typo fixes --- kernels/src/kernels/cli/__init__.py | 1 - kernels/src/kernels/utils.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/kernels/src/kernels/cli/__init__.py b/kernels/src/kernels/cli/__init__.py index 36ce1b2b..86dd0aa5 100644 --- a/kernels/src/kernels/cli/__init__.py +++ b/kernels/src/kernels/cli/__init__.py @@ -333,7 +333,6 @@ def lock_kernels(args): all_locks = [] for kernel, version in kernel_versions.items(): - print(f"Locking `{kernel}` at version {version}", file=sys.stderr) all_locks.append(get_kernel_locks(kernel, version)) with open(args.project_dir / "kernels.lock", "w") as f: diff --git a/kernels/src/kernels/utils.py b/kernels/src/kernels/utils.py index dc96d2ad..ec8e3a33 100644 --- a/kernels/src/kernels/utils.py +++ b/kernels/src/kernels/utils.py @@ -448,9 +448,9 @@ def has_kernel( `bool`: `True` if a kernel is available for the current environment. """ revision = select_revision_or_version(repo_id, revision=revision, version=version) - api = _get_hf_api() package_name = package_name_from_repo_id(repo_id) + api = _get_hf_api() for variant in _build_variants(backend): for init_file in ["__init__.py", f"{package_name}/__init__.py"]: if api.file_exists( From 6692cafa25474df603177506ea8253ca79d5f42d Mon Sep 17 00:00:00 2001 From: drbh Date: Wed, 25 Feb 2026 15:07:47 -0500 Subject: [PATCH 4/4] fix: adjust for mypy --- kernels/src/kernels/status.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernels/src/kernels/status.py b/kernels/src/kernels/status.py index 9cb82a7f..f22cc099 100644 --- a/kernels/src/kernels/status.py +++ b/kernels/src/kernels/status.py @@ -31,9 +31,8 @@ def from_dict(data: dict) -> "Redirect": KernelStatusKind = Union[Redirect] -@dataclass class KernelStatus: - + @staticmethod def from_toml(content: str) -> KernelStatusKind: data = tomllib.loads(content) @@ -47,6 +46,7 @@ def from_toml(content: str) -> KernelStatusKind: raise ValueError(f"Unknown kernel status kind: {kind!r}") # Fetch the kernel status from the repository, if it exists + @staticmethod def check_status( api: HfApi, repo_id: str, revision: str ) -> KernelStatusKind | None: