From a3299dcfc3ed7520a3fc71b2e1c1d8a994d54d1b Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Mon, 31 Aug 2026 20:01:49 +0300 Subject: [PATCH] fix(lab): avoid runtime typing on Python 3.9 --- .../Install-LabV1ComponentAdapterImages.ps1 | 2 +- .../portable_lab_v1_component_adapter.py | 6 +++--- ...st_lab_v1_component_adapter_image_installer.py | 2 +- ...ervatory_portable_lab_v1_component_adapters.py | 15 +++++++++++++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/experiments/perception/worker/observatory_portable/Install-LabV1ComponentAdapterImages.ps1 b/experiments/perception/worker/observatory_portable/Install-LabV1ComponentAdapterImages.ps1 index 3a58782..bc50052 100644 --- a/experiments/perception/worker/observatory_portable/Install-LabV1ComponentAdapterImages.ps1 +++ b/experiments/perception/worker/observatory_portable/Install-LabV1ComponentAdapterImages.ps1 @@ -11,7 +11,7 @@ $ProgressPreference = "SilentlyContinue" $RuntimeRoot = [IO.Path]::GetFullPath("D:\NDC_MISSIONCORE\runtime").TrimEnd("\") $BuildRoot = Join-Path $RuntimeRoot "staging\observatory-lab-v1-build-$SourceRevision" -$SharedAdapterSha256 = "91c1878a58acf3ac35ce894f4de9b63cba3b7f29a65548e28df176063a2953c9" +$SharedAdapterSha256 = "b7dcb3532a65ddc2d6988391056dd2f58f5f631a4db978ebfb5e170bde9c3916" $BuildMethod = "docker-commit-exact-layer-v1" $MaximumLayerBytes = [int64](16MB) diff --git a/experiments/perception/worker/observatory_portable/portable_lab_v1_component_adapter.py b/experiments/perception/worker/observatory_portable/portable_lab_v1_component_adapter.py index c1d5aa9..f2226dc 100644 --- a/experiments/perception/worker/observatory_portable/portable_lab_v1_component_adapter.py +++ b/experiments/perception/worker/observatory_portable/portable_lab_v1_component_adapter.py @@ -23,7 +23,7 @@ import zlib from collections.abc import Callable, Mapping, Sequence from dataclasses import dataclass from pathlib import Path, PurePosixPath -from typing import Final, Literal, cast +from typing import Final, Literal, Optional, cast REQUEST_SCHEMA: Final = "missioncore.observatory-portable-lab-v1-component-request/v1" SOURCE_SCHEMA: Final = "missioncore.observatory-portable-lab-v1-source/v1" @@ -73,7 +73,7 @@ _CAMERA_JOB_ID = re.compile(r"^recorded-camera-[a-f0-9]{24}$") Component = Literal["eomt", "ddrnet"] AssetKind = Literal["file", "tree"] AssetVerification = Literal["sha256", "identity-sha256"] -CommandRunner = Callable[[Sequence[str], Mapping[str, str] | None], None] +CommandRunner = Callable[[Sequence[str], Optional[Mapping[str, str]]], None] # noqa: UP045 class ComponentAdapterError(RuntimeError): @@ -792,7 +792,7 @@ def _paths(value: object, component: Component) -> dict[str, str | None]: _exact_keys(document, set(expected), "component paths") if document != expected: raise ComponentAdapterError("component path contract changed") - return cast(dict[str, str | None], document) + return cast(dict[str, Optional[str]], document) # noqa: UP045 def _asset_bindings( diff --git a/tests/test_lab_v1_component_adapter_image_installer.py b/tests/test_lab_v1_component_adapter_image_installer.py index 962c6c5..1445437 100644 --- a/tests/test_lab_v1_component_adapter_image_installer.py +++ b/tests/test_lab_v1_component_adapter_image_installer.py @@ -41,7 +41,7 @@ def test_component_image_installer_binds_bases_and_adapter_sources() -> None: for digest in ( "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794", "591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd", - "91c1878a58acf3ac35ce894f4de9b63cba3b7f29a65548e28df176063a2953c9", + "b7dcb3532a65ddc2d6988391056dd2f58f5f631a4db978ebfb5e170bde9c3916", "b48ef255403abcfd177a6550688410a52b0fbd29d2a54c8417cb5a0daa330ad5", "a398a43fe4069bf1b1fc2ec61b44df53dad6072cccb6d10a2627e76a96a94056", ): diff --git a/tests/test_observatory_portable_lab_v1_component_adapters.py b/tests/test_observatory_portable_lab_v1_component_adapters.py index cdefa86..edd0670 100644 --- a/tests/test_observatory_portable_lab_v1_component_adapters.py +++ b/tests/test_observatory_portable_lab_v1_component_adapters.py @@ -1,5 +1,6 @@ from __future__ import annotations +import ast import hashlib import json import shutil @@ -35,6 +36,20 @@ def test_component_entrypoints_keep_the_legacy_python39_syntax_floor() -> None: for path in paths: source = path.read_text(encoding="utf-8") assert "\ntype " not in source + module = ast.parse(source, filename=str(path), feature_version=(3, 9)) + for statement in module.body: + if isinstance(statement, ast.Assign): + assert not any( + isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr) + for node in ast.walk(statement.value) + ), f"runtime-evaluated PEP 604 alias in {path.name}" + for call in (node for node in ast.walk(module) if isinstance(node, ast.Call)): + if isinstance(call.func, ast.Name) and call.func.id == "cast": + assert call.args + assert not any( + isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr) + for node in ast.walk(call.args[0]) + ), f"runtime-evaluated PEP 604 cast in {path.name}" assert "slots=True" not in paths[0].read_text(encoding="utf-8") assert "slots=True" not in paths[2].read_text(encoding="utf-8")