From 02033fdab209b665e88ee6a666d6266a230b80c6 Mon Sep 17 00:00:00 2001 From: John Tsui <110079544+JohnXu22786@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:46:55 +0800 Subject: [PATCH] fix(queries): include top-level dependents Reverse dependency queries must include consumers that import top-level modules through the root package. --- src/codegraph/queries.py | 4 ++-- tests/test_queries.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/codegraph/queries.py b/src/codegraph/queries.py index 84feaf6..c94e562 100644 --- a/src/codegraph/queries.py +++ b/src/codegraph/queries.py @@ -173,8 +173,8 @@ def query_dependents(store: IndexStore, module: str, limit: int = 200): for r in rows] seen = {r["path"] for r in results} mod = file["module"] or "" - if "." in mod: - base, name = mod.rsplit(".", 1) + if mod: + base, _, name = mod.rpartition(".") # Match plain JSON tokens with instr(); for aliases, normalize JSON's # escaped tabs and use GLOB so arbitrary spaces/tabs around ``as`` # work. Relative imports (module ".") count too when the importing diff --git a/tests/test_queries.py b/tests/test_queries.py index e66c47d..9b96777 100644 --- a/tests/test_queries.py +++ b/tests/test_queries.py @@ -613,6 +613,24 @@ def test_dependents_via_relative_import(self): finally: store.close() + def test_dependents_via_top_level_relative_import(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "__init__.py").write_text( + "from . import sibling\n", encoding="utf-8") + (root / "sibling.py").write_text( + "def deliver(item):\n return item\n", encoding="utf-8") + cfg = load_config(root=str(root)) + cfg.engine = "quick" + build_index(cfg) + store = IndexStore(str(cfg.db_path)) + try: + rows = query_dependents(store, "sibling") + self.assertEqual( + [row["path"] for row in rows], ["__init__.py"]) + finally: + store.close() + def test_relative_import_does_not_match_package_prefix(self): """A sibling package with a shared prefix is not a dependent.""" with tempfile.TemporaryDirectory() as tmp: