Files
wehub-resource-sync 09e9f3545f
CodeQL / Analyze (push) Waiting to run
dependency-audit / pip-audit (push) Waiting to run
Test / Code Quality (push) Has been cancelled
Test / Test (macos-latest, Python 3.10) (push) Has been cancelled
Test / Test (macos-latest, Python 3.11) (push) Has been cancelled
Test / Test (macos-latest, Python 3.12) (push) Has been cancelled
Test / Test (macos-latest, Python 3.13) (push) Has been cancelled
Test / Test (macos-latest, Python 3.14) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.10) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.11) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.12) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.13) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.14) (push) Has been cancelled
Test / Test (windows-latest, Python 3.10) (push) Has been cancelled
Test / Test (windows-latest, Python 3.11) (push) Has been cancelled
Test / Test (windows-latest, Python 3.12) (push) Has been cancelled
Test / Test (windows-latest, Python 3.13) (push) Has been cancelled
Test / Test (windows-latest, Python 3.14) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:30:13 +08:00

168 lines
5.5 KiB
Python

"""Typing checks for the capability-Protocol contracts in
``notebooklm._runtime.contracts``.
Phase 7 (docs/refactor-history.md §Migration Plan step 10) replaced the broad
``Session`` Protocol with shared capability Protocols. The surviving
shared Protocols are ``RpcCaller`` (~17 consumers), ``LoopGuard`` (2
consumers), and the pure-transport ``Kernel``. The single-consumer
``AuthMetadata`` / ``OperationScopeProvider`` Protocols and the unused
``AsyncWorkRuntime`` composite were inlined into their owning feature
modules / deleted in issue #1327 — ``AuthMetadata`` now lives in
``_source.upload`` (used by ``SourceUploadPipeline``) and
``OperationScopeProvider`` in ``_artifact.polling`` (used by
``ArtifactPollingService``); mypy enforces their structural conformance
at the consuming call sites. The standalone
``DrainHookRegistration`` Protocol previously kept here was deleted in
Phase 7; drain-hook registration now lives on
``TransportDrainTracker.register_drain_hook(...)`` in ``_transport_drain.py``.
"""
from __future__ import annotations
import inspect
from collections.abc import Mapping
from typing import Any
import httpx
from notebooklm._runtime.contracts import (
Kernel,
LoopGuard,
RpcCaller,
)
from notebooklm.rpc.types import RPCMethod
class _RpcCallerImpl:
async def rpc_call(
self,
method: RPCMethod,
params: list[Any],
source_path: str = "/",
allow_null: bool = False,
_is_retry: bool = False,
*,
disable_internal_retries: bool = False,
operation_variant: str | None = None,
) -> Any:
return None
class _LoopGuardImpl:
def assert_bound_loop(self) -> None:
return None
class _KernelImpl:
async def post(
self,
url: str,
headers: Mapping[str, str],
body: bytes,
*,
read_timeout: float | None = None,
max_response_bytes: int | None = None,
) -> httpx.Response:
return httpx.Response(200, content=body)
@property
def cookies(self) -> httpx.Cookies:
return httpx.Cookies()
async def aclose(self) -> None:
return None
def _public_contract_members(protocol: type[Any]) -> set[str]:
return {name for name in protocol.__dict__ if not name.startswith("_")}
# ----------------------------------------------------------------------
# Membership pins — one test per Protocol
# ----------------------------------------------------------------------
def test_kernel_protocol_has_exactly_three_members() -> None:
assert _public_contract_members(Kernel) == {"post", "cookies", "aclose"}
def test_rpc_caller_protocol_has_exactly_one_member() -> None:
assert _public_contract_members(RpcCaller) == {"rpc_call"}
def test_loop_guard_protocol_has_exactly_one_member() -> None:
assert _public_contract_members(LoopGuard) == {"assert_bound_loop"}
# ----------------------------------------------------------------------
# Signature pins — load-bearing for feature retypes
# ----------------------------------------------------------------------
def test_rpc_caller_signature_matches_legacy_session_rpc_call() -> None:
sig = inspect.signature(RpcCaller.rpc_call)
assert list(sig.parameters) == [
"self",
"method",
"params",
"source_path",
"allow_null",
"_is_retry",
"disable_internal_retries",
"operation_variant",
]
assert sig.parameters["source_path"].default == "/"
assert sig.parameters["allow_null"].default is False
assert sig.parameters["_is_retry"].default is False
assert sig.parameters["disable_internal_retries"].kind is inspect.Parameter.KEYWORD_ONLY
assert sig.parameters["disable_internal_retries"].default is False
assert sig.parameters["operation_variant"].kind is inspect.Parameter.KEYWORD_ONLY
assert sig.parameters["operation_variant"].default is None
def test_kernel_protocol_signatures_are_pinned() -> None:
post = inspect.signature(Kernel.post)
assert list(post.parameters) == [
"self",
"url",
"headers",
"body",
"read_timeout",
"max_response_bytes",
]
assert post.parameters["headers"].annotation == "Mapping[str, str]"
assert post.parameters["body"].annotation == "bytes"
assert post.parameters["read_timeout"].kind is inspect.Parameter.KEYWORD_ONLY
assert post.parameters["read_timeout"].default is None
assert post.parameters["max_response_bytes"].kind is inspect.Parameter.KEYWORD_ONLY
assert post.parameters["max_response_bytes"].default is None
assert post.return_annotation == "httpx.Response"
cookies = inspect.signature(Kernel.cookies.fget)
assert cookies.return_annotation == "httpx.Cookies"
aclose = inspect.signature(Kernel.aclose)
assert list(aclose.parameters) == ["self"]
assert aclose.return_annotation == "None"
def test_loop_guard_signature_is_pinned() -> None:
sig = inspect.signature(LoopGuard.assert_bound_loop)
assert list(sig.parameters) == ["self"]
assert sig.return_annotation == "None"
# ----------------------------------------------------------------------
# Structural conformance — mypy verifies these assignments
# ----------------------------------------------------------------------
def test_structural_implementations_satisfy_protocols() -> None:
kernel: Kernel = _KernelImpl()
rpc: RpcCaller = _RpcCallerImpl()
loop_guard: LoopGuard = _LoopGuardImpl()
assert kernel is not None
assert rpc is not None
assert loop_guard is not None