chore(types): add pyright strict config and fix resulting errors
test / unit (push) Successful in 11s
test / integration (push) Successful in 12s

Adds pyrightconfig.json (strict, Python 3.11) covering cli.py,
claude_bottle/, and tests/. Fixes the 49 strict-mode errors:

- Type DockerBottle.teardown as Callable[[], None].
- ResolvedEnv default_factory uses parameterized list[str] / dict[str, str].
- Erase BottleBackend generics at the registry boundary
  (BottleBackend[Any, Any]) since selection is runtime-driven and
  callers use the unparameterized interface.
- DockerBottleBackend.launch returns Generator[DockerBottle, None, None];
  @contextmanager now flags Iterator returns as deprecated.
- Sidestep cli.list submodule shadowing builtins.list in main()'s argv
  annotation via an aliased re-import in cli/__init__.py.
- Cast cfg[...] results in test_pipelock_yaml at the dict[str, object]
  boundary.
- Annotate write_fixture's fn parameter and _manifest_with_runtime's
  return type.
This commit is contained in:
2026-05-12 10:03:48 -04:00
parent ac634edcb6
commit 64a31a382b
9 changed files with 50 additions and 20 deletions
+7 -5
View File
@@ -34,7 +34,7 @@ from abc import ABC, abstractmethod
from contextlib import AbstractContextManager
from dataclasses import dataclass
from pathlib import Path
from typing import Generic, TypeVar
from typing import Any, Generic, TypeVar
from ..log import die
from ..manifest import Manifest
@@ -199,14 +199,16 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
from .docker import DockerBottleBackend # noqa: E402
# The dict carries heterogeneous BottleBackend specializations; callers
# use it through the unparameterized BottleBackend interface.
_BACKENDS: dict[str, BottleBackend] = {
# The dict is heterogeneous: each value is a BottleBackend specialized
# over its own plan type. Concrete plan types are erased here because
# the registry is selected at runtime and the CLI only needs the
# unparameterized methods (prepare → plan → launch(plan), cleanup, etc.).
_BACKENDS: dict[str, BottleBackend[Any, Any]] = {
"docker": DockerBottleBackend(),
}
def get_bottle_backend() -> BottleBackend:
def get_bottle_backend() -> BottleBackend[Any, Any]:
"""Resolve the bottle backend for the active environment. Dies with
a pointer at the known backends if CLAUDE_BOTTLE_BACKEND names an
unimplemented one."""
+2 -2
View File
@@ -16,7 +16,7 @@ import subprocess
import sys
from contextlib import ExitStack, contextmanager
from pathlib import Path
from typing import Iterator, Sequence
from typing import Generator, Sequence
from ... import pipelock
from ...env import ResolvedEnv, resolve_env
@@ -165,7 +165,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
env_file.chmod(0o600)
@contextmanager
def launch(self, plan: DockerBottlePlan) -> Iterator[DockerBottle]:
def launch(self, plan: DockerBottlePlan) -> Generator[DockerBottle, None, None]:
"""Build, launch, and provision a Docker bottle. Teardown on exit."""
stack = ExitStack()
+7 -1
View File
@@ -9,6 +9,7 @@ prompt was provisioned.
from __future__ import annotations
import subprocess
from typing import Callable
from .. import Bottle
@@ -16,7 +17,12 @@ from .. import Bottle
class DockerBottle(Bottle):
"""Concrete Bottle for Docker."""
def __init__(self, container: str, teardown, prompt_path_in_container: str | None):
def __init__(
self,
container: str,
teardown: Callable[[], None],
prompt_path_in_container: str | None,
):
self.name = container
self._teardown = teardown
self._prompt_path = prompt_path_in_container