fix(backend): fix pyright errors in lazy-load implementation
- Rename _BACKENDS → _backends: pyright treats uppercase module-level names as constants and flags the reassignment in _get_backends() as reportConstantRedefinition; lowercase avoids this. - Add TYPE_CHECKING guard importing CommitCancelled/Freezer/get_freezer from .freeze: pyright cannot see module-level __getattr__ bindings, so reportUnsupportedDunderAll fired for those three __all__ entries; the guard makes them visible to the type checker without running at import time. - Update test_backend_selection.py to patch _backends (lowercase).
This commit is contained in:
@@ -40,7 +40,7 @@ from abc import ABC, abstractmethod
|
|||||||
from contextlib import AbstractContextManager
|
from contextlib import AbstractContextManager
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Generic, Sequence, TypeVar
|
from typing import TYPE_CHECKING, Any, Generic, Sequence, TypeVar
|
||||||
|
|
||||||
from ..agent_provider import AgentProvisionPlan, get_provider, build_agent_provision_plan
|
from ..agent_provider import AgentProvisionPlan, get_provider, build_agent_provision_plan
|
||||||
from ..egress import EgressPlan
|
from ..egress import EgressPlan
|
||||||
@@ -54,6 +54,9 @@ from ..workspace import WorkspacePlan, workspace_plan
|
|||||||
from .print_util import print_multi, visible_agent_env_names
|
from .print_util import print_multi, visible_agent_env_names
|
||||||
from .util import host_skill_dir
|
from .util import host_skill_dir
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .freeze import CommitCancelled, Freezer, get_freezer
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class BottleSpec:
|
class BottleSpec:
|
||||||
@@ -572,31 +575,31 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
|
|||||||
Not called by the launch path or the test suite."""
|
Not called by the launch path or the test suite."""
|
||||||
|
|
||||||
|
|
||||||
# _BACKENDS is None until the first call to _get_backends(), at which
|
# _backends is None until the first call to _get_backends(), at which
|
||||||
# point all three concrete backend classes are imported and instantiated.
|
# point all three concrete backend classes are imported and instantiated.
|
||||||
# Keeping the imports out of module scope means that importing any
|
# Keeping the imports out of module scope means that importing any
|
||||||
# backend sub-module (e.g. `backend.docker.util`) no longer drags the
|
# backend sub-module (e.g. `backend.docker.util`) no longer drags the
|
||||||
# firecracker and macos-container implementations into memory.
|
# firecracker and macos-container implementations into memory.
|
||||||
#
|
#
|
||||||
# Tests may replace _BACKENDS with a {name: fake} dict via patch.object;
|
# Tests may replace _backends with a {name: fake} dict via patch.object;
|
||||||
# _get_backends() returns the current module-level value as-is when it
|
# _get_backends() returns the current module-level value as-is when it
|
||||||
# is not None, so test fakes take effect without triggering real imports.
|
# is not None, so test fakes take effect without triggering real imports.
|
||||||
_BACKENDS: dict[str, BottleBackend[Any, Any]] | None = None
|
_backends: dict[str, BottleBackend[Any, Any]] | None = None
|
||||||
|
|
||||||
|
|
||||||
def _get_backends() -> dict[str, BottleBackend[Any, Any]]:
|
def _get_backends() -> dict[str, BottleBackend[Any, Any]]:
|
||||||
"""Return the registry of all backend instances, loading lazily on first call."""
|
"""Return the registry of all backend instances, loading lazily on first call."""
|
||||||
global _BACKENDS # pylint: disable=global-statement
|
global _backends # pylint: disable=global-statement
|
||||||
if _BACKENDS is None:
|
if _backends is None:
|
||||||
from .docker import DockerBottleBackend
|
from .docker import DockerBottleBackend
|
||||||
from .firecracker import FirecrackerBottleBackend
|
from .firecracker import FirecrackerBottleBackend
|
||||||
from .macos_container import MacosContainerBottleBackend
|
from .macos_container import MacosContainerBottleBackend
|
||||||
_BACKENDS = {
|
_backends = {
|
||||||
"docker": DockerBottleBackend(),
|
"docker": DockerBottleBackend(),
|
||||||
"firecracker": FirecrackerBottleBackend(),
|
"firecracker": FirecrackerBottleBackend(),
|
||||||
"macos-container": MacosContainerBottleBackend(),
|
"macos-container": MacosContainerBottleBackend(),
|
||||||
}
|
}
|
||||||
return _BACKENDS
|
return _backends
|
||||||
|
|
||||||
|
|
||||||
def __getattr__(name: str) -> Any:
|
def __getattr__(name: str) -> Any:
|
||||||
@@ -717,12 +720,12 @@ __all__ = [
|
|||||||
"BottleCleanupPlan",
|
"BottleCleanupPlan",
|
||||||
"BottlePlan",
|
"BottlePlan",
|
||||||
"BottleSpec",
|
"BottleSpec",
|
||||||
"CommitCancelled", # pylint: disable=undefined-all-variable
|
"CommitCancelled",
|
||||||
"ExecResult",
|
"ExecResult",
|
||||||
"Freezer", # pylint: disable=undefined-all-variable
|
"Freezer",
|
||||||
"enumerate_active_agents",
|
"enumerate_active_agents",
|
||||||
"get_bottle_backend",
|
"get_bottle_backend",
|
||||||
"get_freezer", # pylint: disable=undefined-all-variable
|
"get_freezer",
|
||||||
"has_backend",
|
"has_backend",
|
||||||
"known_backend_names",
|
"known_backend_names",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class TestGetBottleBackend(unittest.TestCase):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
with patch.dict(os.environ, {}, clear=True), \
|
with patch.dict(os.environ, {}, clear=True), \
|
||||||
patch.object(backend_mod, "_BACKENDS", {
|
patch.object(backend_mod, "_backends", {
|
||||||
"macos-container": _FakeBackend(),
|
"macos-container": _FakeBackend(),
|
||||||
"docker": _FakeBackend(),
|
"docker": _FakeBackend(),
|
||||||
}):
|
}):
|
||||||
@@ -61,7 +61,7 @@ class TestGetBottleBackend(unittest.TestCase):
|
|||||||
with patch.dict(os.environ, {}, clear=True), \
|
with patch.dict(os.environ, {}, clear=True), \
|
||||||
patch.object(backend_mod.FirecrackerBottleBackend,
|
patch.object(backend_mod.FirecrackerBottleBackend,
|
||||||
"is_host_capable", classmethod(lambda cls: False)), \
|
"is_host_capable", classmethod(lambda cls: False)), \
|
||||||
patch.object(backend_mod, "_BACKENDS", {
|
patch.object(backend_mod, "_backends", {
|
||||||
"macos-container": _FakeBackend("macos-container", False),
|
"macos-container": _FakeBackend("macos-container", False),
|
||||||
"docker": _FakeBackend("docker", True),
|
"docker": _FakeBackend("docker", True),
|
||||||
}):
|
}):
|
||||||
@@ -83,7 +83,7 @@ class TestGetBottleBackend(unittest.TestCase):
|
|||||||
with patch.dict(os.environ, {}, clear=True), \
|
with patch.dict(os.environ, {}, clear=True), \
|
||||||
patch.object(backend_mod.FirecrackerBottleBackend,
|
patch.object(backend_mod.FirecrackerBottleBackend,
|
||||||
"is_host_capable", classmethod(lambda cls: True)), \
|
"is_host_capable", classmethod(lambda cls: True)), \
|
||||||
patch.object(backend_mod, "_BACKENDS", {
|
patch.object(backend_mod, "_backends", {
|
||||||
"macos-container": _FakeBackend("macos-container", False),
|
"macos-container": _FakeBackend("macos-container", False),
|
||||||
"firecracker": _FakeBackend("firecracker", False),
|
"firecracker": _FakeBackend("firecracker", False),
|
||||||
"docker": _FakeBackend("docker", True),
|
"docker": _FakeBackend("docker", True),
|
||||||
@@ -133,7 +133,7 @@ class TestEnumerateActiveAgents(unittest.TestCase):
|
|||||||
return self._items
|
return self._items
|
||||||
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
backend_mod, "_BACKENDS",
|
backend_mod, "_backends",
|
||||||
{"docker": _FakeBackend([a]), "firecracker": _FakeBackend([b])},
|
{"docker": _FakeBackend([a]), "firecracker": _FakeBackend([b])},
|
||||||
):
|
):
|
||||||
self.assertEqual([a, b], enumerate_active_agents())
|
self.assertEqual([a, b], enumerate_active_agents())
|
||||||
@@ -167,7 +167,7 @@ class TestEnumerateActiveAgents(unittest.TestCase):
|
|||||||
return self._items
|
return self._items
|
||||||
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
backend_mod, "_BACKENDS",
|
backend_mod, "_backends",
|
||||||
{
|
{
|
||||||
"docker": _FakeBackend([newer, tie_b]),
|
"docker": _FakeBackend([newer, tie_b]),
|
||||||
"firecracker": _FakeBackend([missing_metadata, tie_a]),
|
"firecracker": _FakeBackend([missing_metadata, tie_a]),
|
||||||
@@ -187,7 +187,7 @@ class TestEnumerateActiveAgents(unittest.TestCase):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
backend_mod, "_BACKENDS",
|
backend_mod, "_backends",
|
||||||
{"docker": _FakeBackend(), "firecracker": _FakeBackend()},
|
{"docker": _FakeBackend(), "firecracker": _FakeBackend()},
|
||||||
):
|
):
|
||||||
self.assertEqual([], enumerate_active_agents())
|
self.assertEqual([], enumerate_active_agents())
|
||||||
@@ -218,7 +218,7 @@ class TestEnumerateActiveAgents(unittest.TestCase):
|
|||||||
return self._items
|
return self._items
|
||||||
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
backend_mod, "_BACKENDS",
|
backend_mod, "_backends",
|
||||||
{
|
{
|
||||||
"docker": _FakeBackend([present], available=True),
|
"docker": _FakeBackend([present], available=True),
|
||||||
"firecracker": _FakeBackend([hidden], available=False),
|
"firecracker": _FakeBackend([hidden], available=False),
|
||||||
@@ -234,7 +234,7 @@ class TestHasBackend(unittest.TestCase):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
backend_mod, "_BACKENDS", {"docker": _FakeBackend()},
|
backend_mod, "_backends", {"docker": _FakeBackend()},
|
||||||
):
|
):
|
||||||
from bot_bottle.backend import has_backend
|
from bot_bottle.backend import has_backend
|
||||||
self.assertFalse(has_backend("docker"))
|
self.assertFalse(has_backend("docker"))
|
||||||
|
|||||||
Reference in New Issue
Block a user