diff --git a/python/tests/test_repo_hygiene.py b/python/tests/test_repo_hygiene.py index 0c329be..1f78644 100644 --- a/python/tests/test_repo_hygiene.py +++ b/python/tests/test_repo_hygiene.py @@ -46,8 +46,22 @@ re.compile(r"ali-pod\d"), ] -_MLX_IMPORT = re.compile(r"^\s*(?:from\s+mlx(?:\s|\.)|import\s+mlx(?:\s|\.))", - re.MULTILINE) +# ``\b`` after ``mlx(?:_lm)?`` matches ``import mlx``, ``import mlx.core``, +# ``from mlx_lm.models...`` and ``from mlx_lm import ...`` alike, while a +# hypothetical ``mlxfoo`` package still does not match. The previous +# pattern required a space or dot right after ``mlx`` and therefore let +# ``mlx_lm`` imports through. +_MLX_IMPORT = re.compile(r"^\s*(?:from|import)\s+mlx(?:_lm)?\b", re.MULTILINE) + +# Files outside ``backends/mlx`` that currently import MLX packages. Each +# entry is a known boundary violation tracked for removal; delete the entry +# once the import is gone so the guard starts enforcing it again. +_MLX_IMPORT_KNOWN_VIOLATIONS = { + # ``_gather_sort`` / ``_scatter_unsort`` come from + # ``mlx_lm.models.switch_layers``; they should move into the framework + # so the streaming layer is importable on other backends. + "python/src/edge0/streaming/layer.py", +} _SECRET_PATTERNS = [ re.compile(r"\bsk-[A-Za-z0-9_-]{20,}\b"), @@ -122,7 +136,10 @@ def test_mlx_imports_stay_inside_the_backend(): for path in (ROOT / "python" / "src" / "edge0").rglob("*.py"): rel = path.relative_to(ROOT) text = path.read_text(encoding="utf-8") - if _MLX_IMPORT.search(text) and "backends/mlx" not in rel.as_posix(): + posix = rel.as_posix() + if "backends/mlx" in posix or posix in _MLX_IMPORT_KNOWN_VIOLATIONS: + continue + if _MLX_IMPORT.search(text): bad.append(str(rel)) assert not bad, ( "MLX imports must live under edge0/backends/mlx/ only:\n"