fix(resolution): decline Python module-scope collection method guesses (#1652) - #1776
Merged
colbymchenry merged 1 commit intoSep 8, 2026
Merged
Conversation
Use same-file module variable initializers to filter builtin collection calls before class-name heuristics, and require a Python type node for the class escape. Preserve imported project module calls. Add callers/callees regressions for dict, list, set, tuple, and frozenset, with a real instance control and same-name bindings across files. Validation on Linux with Node 22.19.0: the new suite had 14 failures and one passing control on main at 8733c28; all 216 tests in the new suite, call-receiver-no-fabrication, and resolution now pass. TypeScript and copy-assets pass. Re-indexed /tmp/cg-1652-repro: callers get is empty and read_setting no longer calls a cache.py method.
colbymchenry
deleted the
forge/fix-1652-python-module-scope-dict-methods
branch
September 8, 2026 15:29
bompus
added a commit
to bompus/codegraph
that referenced
this pull request
Sep 8, 2026
Second reconcile of the day. Upstream landed colbymchenry#1776 and colbymchenry#1778 after this morning's merge (82cf9f0), and colbymchenry#1778 rewrote the lua variable-pairing code in both arms, where the fork hangs markdown references off the node it creates. Three conflicts, two of them the same collision twice. true merge, both sides needed: codegraph-kernel/src/lua.rs upstream's `value.map(...)` replaces the fork's `values.get(i).map(...)`; the fork's `let row = self.create_node(` is kept because the markdown-refs block below the conflict binds `row` and merged cleanly, so upstream's side alone does not compile. src/extraction/tree-sitter.ts the same shape in the WASM arm: upstream's `target.name` with the fork's `const varNode` capture and extractMarkdownPathReferences call. union, upstream only: CHANGELOG.md the fork side is empty, so this is upstream's colbymchenry#1652 and colbymchenry#1730/colbymchenry#1731 entries verbatim.
inth3shadows
added a commit
to inth3shadows/codegraph
that referenced
this pull request
Sep 8, 2026
The maintainer asked on colbymchenry#1704 to drop the bits that were landing separately once colbymchenry#1749 merged. Both named PRs are on main now (colbymchenry#1748 bb1d309, colbymchenry#1749 edcd36e), along with three more python-resolution changes the same morning, so this reconciles against all of them rather than only the two. Six conflicts, resolved by what each side is now the authority on: - src/resolution/index.ts — take main in all three hunks. Its isPythonProjectModule is our own, byte-identical apart from one comment, so ours is deleted rather than merged; git had auto-merged both copies into a duplicate definition. Its isKnownClass is the stricter colbymchenry#1776 version, and the collection-binding filter now short-circuits before the class escape. - __tests__/resolution.test.ts — take main. Our +54 was subsumed by its +347; the delta of this branch against main for that file is now zero, which is exactly what was asked for. - src/extraction/tree-sitter.ts and codegraph-kernel/src/python.rs — keep both arms, main's first. colbymchenry#1748 claims the call-chain receiver (`d.setdefault(k, []).append(v)`) and encodes it as `<inner>().<method>`; ours stays the catch-all beneath it for the shapes that arm does not match, the attribute chain (`self.data.append`) and the subscript (`d[k].append`). The comments on both arms said they covered the call-chain shape and no longer do, so they are corrected in place. - __tests__/fixtures/kernel-parity/torture.py — union. bucket_chains keeps the call receivers; fabrication_shapes keeps a real attribute chain and a subscript, since its former call-chain line is now bucket_chains' job. What this branch still carries that main does not: the python attribute-type inference read from the AST, the chained-receiver gate, the kernel mirror for non-call receivers, the branch-guard changes and the module-suffix index. Verified: tsc --noEmit clean; npm test 4226 passed / 238 files. The three remaining failures (object-literal-methods, two in ui-steps-api) reproduce on a clean upstream/main worktree at ee83636 and are not from this merge; a fourth, ui-server-api's "under 100 ms", is a wall-clock assertion that passed and then failed at 113ms in the same command. NOT verified: the Rust arm. There is no cargo on this machine, so every kernel-*-parity suite describe.skipIf's itself and the python.rs change is unexercised.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1652.
Python calls like
DEFAULTS.get(name)on a module-scope dict (or other builtin collection) were resolving to unrelated project methods (LRUCache.get) viainstance-methodsingle-survivor matching.Root cause:
isBuiltInOrExternal's "known class" escape usedknownNames.has(capitalized), andknownNamesincludes variables. The variableDEFAULTSitself punched through the builtin-method filter;matchMethodCallStrategy 3 then bound the only Python method namedget.Fix (receiver-type gate, as preferred on the issue):
{}/[]/dict()/list()/set()/tuple()/frozenset(), etc.).class/struct/interfacenode for the class escape (not any known name).#1681imported-project-module escape.Tests
__tests__/python-module-scope-collection-methods.test.ts— issue fixture, collection variants, unknown binding, real annotated instance control.call-receiver-no-fabrication(Call-expression receivers drop the receiver and fabricate a calls edge to any same-named top-level symbol — Python AND JavaScript, live in 1.6.0 #1683),resolutionincluding Python: a top-level function named like a collection method (append/update/get) gets ZERO real callers and fabricated ones — uncovered shapes left by #715 and #1317, live in 1.6.0 #1681 (216 tests total in that trio).Verify (Linux)
8733c288; 15/15 with this change.codegraph callers get --json→[];read_settingno longer callscache.pymethods.Related open PR #1704 is broader (attr-type / branch-guard / kernel); this PR is the focused #1652 slice only.