test(workspace): verify distribution boundaries

This commit is contained in:
2026-07-12 14:14:09 +08:00
parent 00bf5ee428
commit 351b2c6637
2 changed files with 69 additions and 1 deletions
@@ -11,7 +11,7 @@
- [x] 2.1 Move the existing `cloud` package under `packages/cloud-platform` while preserving every `cloud.*` import path.
- [x] 2.2 Remove `cloud*` from the root distribution's setuptools discovery and update path-sensitive composition tests or tooling.
- [ ] 2.3 Add packaging tests that identify the owning distribution for Runtime and cloud modules and reject reverse cloud dependencies.
- [x] 2.3 Add packaging tests that identify the owning distribution for Runtime and cloud modules and reject reverse cloud dependencies.
## 3. Locking And Developer Commands
+68
View File
@@ -0,0 +1,68 @@
from __future__ import annotations
import ast
import re
import tomllib
from importlib.metadata import packages_distributions
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
RUNTIME_PACKAGE_DIRS = (
"agents",
"api",
"core",
"device",
"driver",
"perception",
"runtime",
"semantic",
"skills_learning",
"storage",
"tools",
"workflow",
"world",
)
def test_workspace_distributions_own_expected_import_packages() -> None:
distributions = packages_distributions()
assert distributions.get("cloud") == ["device-cloud-platform"]
assert distributions.get("core") == ["device-agent-runtime"]
assert distributions.get("runtime") == ["device-agent-runtime"]
def test_runtime_project_does_not_declare_cloud_distribution() -> None:
project = tomllib.loads((PROJECT_ROOT / "pyproject.toml").read_text("utf-8"))
dependencies = {
_requirement_name(requirement)
for requirement in project["project"].get("dependencies", [])
}
package_patterns = project["tool"]["setuptools"]["packages"]["find"]["include"]
assert "device-cloud-platform" not in dependencies
assert "cloud*" not in package_patterns
def test_runtime_source_does_not_import_cloud() -> None:
offenders: list[str] = []
for package_dir in RUNTIME_PACKAGE_DIRS:
for path in (PROJECT_ROOT / package_dir).rglob("*.py"):
tree = ast.parse(path.read_text("utf-8"), filename=str(path))
for node in ast.walk(tree):
if isinstance(node, ast.Import):
names = [alias.name for alias in node.names]
elif isinstance(node, ast.ImportFrom) and node.module:
names = [node.module]
else:
continue
if any(name == "cloud" or name.startswith("cloud.") for name in names):
offenders.append(str(path.relative_to(PROJECT_ROOT)))
assert not offenders, f"runtime distribution imports cloud: {sorted(set(offenders))}"
def _requirement_name(requirement: str) -> str:
name = re.split(r"[\s<>=!~\[]", requirement, maxsplit=1)[0]
return name.lower().replace("_", "-")