69 lines
2.2 KiB
Python
69 lines
2.2 KiB
Python
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("_", "-")
|