From 9c27a524482246aa425bfe8b32e4fba87e4a77ca Mon Sep 17 00:00:00 2001 From: Cekaru Date: Thu, 9 Jul 2026 13:22:36 +0100 Subject: [PATCH] test(extractors): guard facade + registry identity for the per-language split (#1721) The extract_terraform move #1721 proposed already landed on v8 via the #1737 decomposition (extractors/terraform.py exists, extract.py re-exports it, and extractors/LANGUAGE_EXTRACTORS registers it), so the code move is a no-op now. But the regression test @Cekaru added with it had no equivalent on v8. Salvage and generalize it: sweep every LANGUAGE_EXTRACTORS entry and assert graphify. extract re-exports the SAME object (facade identity) and the registry maps to it (registry identity), plus the concrete terraform anchor from the PR. This institutionalizes the re-export-identity guarantee the split relies on, so a future move that forgets a facade re-export fails loudly. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_extractors_registry.py | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/test_extractors_registry.py diff --git a/tests/test_extractors_registry.py b/tests/test_extractors_registry.py new file mode 100644 index 000000000..db647201f --- /dev/null +++ b/tests/test_extractors_registry.py @@ -0,0 +1,44 @@ +"""Facade / registry identity guards for the per-language extractor split (#1212). + +The ``extract.py`` decomposition (#1737) moved each language extractor into its +own ``graphify/extractors/.py`` module, kept a verbatim re-export in +``graphify.extract`` (the facade every existing importer uses), and seeded a +``graphify.extractors.LANGUAGE_EXTRACTORS`` registry. Three things must stay +true for that split to be behavior-preserving: + +- the function is importable from its new per-language module, +- ``graphify.extract`` still re-exports the SAME function object (facade + identity — a stale copy or shadowing import would silently diverge), +- ``LANGUAGE_EXTRACTORS`` maps to that same object (registry identity). + +Originally proposed by @Cekaru in #1721 as a per-language check; generalized +here to sweep the whole registry so a future move that forgets the facade +re-export (or re-exports a different object) fails loudly. +""" +from __future__ import annotations + +import graphify.extract as facade +from graphify.extractors import LANGUAGE_EXTRACTORS + + +def test_every_registry_extractor_is_reexported_from_facade(): + missing = [] + diverged = [] + for lang, fn in LANGUAGE_EXTRACTORS.items(): + name = getattr(fn, "__name__", None) + if not name or not hasattr(facade, name): + missing.append((lang, name)) + continue + if getattr(facade, name) is not fn: + diverged.append((lang, name)) + assert not missing, f"registry extractors not re-exported from graphify.extract: {missing}" + assert not diverged, f"facade object diverges from registry: {diverged}" + + +def test_terraform_migrated(): + # The concrete anchor from #1721: extract_terraform lives in its own module, + # and both the facade and the registry point at that one object. + from graphify.extractors.terraform import extract_terraform + + assert facade.extract_terraform is extract_terraform + assert LANGUAGE_EXTRACTORS["terraform"] is extract_terraform