MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / pythonExternalWrites

Function pythonExternalWrites

src/resolution/name-matcher.ts:773–813  ·  view source on GitHub ↗

* Writes to module global `global` from OTHER files. A production write * ` . = Cls(...)` adds a type; any other production write * (another value, a tuple target, `setattr`) makes the type unknown. Test * files install doubles (`settings.conn = MagicMock()`, `monkeypatch.setattr`)

(global: Node, context: ResolutionContext)

Source from the content-addressed store, hash-verified

771 * a ref inside a writer resolves nothing through the global.
772 */
773function pythonExternalWrites(global: Node, context: ResolutionContext): { writes: Array<{ type: string; file: string }>; unknown: boolean; writers: Set<string> } {
774 return pythonNameScan(context, `external\0${global.id}`, () => {
775 const out = { writes: [] as Array<{ type: string; file: string }>, unknown: false, writers: new Set<string>() };
776 const name = global.name;
777 const escape = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
778 for (const file of context.getAllFiles()) {
779 if (file === global.filePath || !/\.pyi?$/.test(file) || !context.readFile(file)?.includes(name)) continue;
780 const test = isPythonTestFile(file);
781 const { aliases, ambiguous } = pythonModuleAliases(file, global.filePath, context);
782 if (!test && !aliases.length && !ambiguous.length) continue;
783 const spell = (names: string[]) => `(?:${names.map(escape).join('|')})`;
784 // Test files: any receiver (the double may sit on any spelling of the module).
785 const receiver = test ? '[\\w.]+' : spell([...aliases, ...ambiguous]);
786 const target = new RegExp(`(?<![\\w.])${receiver}\\.${name}\\b(?!\\s*[.\\[(])`);
787 const exact = new RegExp(`^${test ? receiver : spell(aliases.length ? aliases : ['\\0'])}\\.${name}(?:\\s*:[^=]*)?$`);
788 const dynamic = new RegExp(`\\b(?:setattr|patch\\.object)\\s*\\(\\s*${receiver}\\s*,\\s*['"]${name}['"]` +
789 `|(?<![\\w.])${receiver}\\.__dict__\\s*(?:\\[|\\.\\s*update\\s*\\()`);
790 const lines = pythonMemberLines(file, context);
791 const statements = pythonStatementStarts(file, context);
792 const script = pythonMainBlockLines(file, context);
793 for (let i = 0; i < lines.length; i++) {
794 if (!statements[i] || script.has(i)) continue;
795 let statement = lines[i]!;
796 for (let j = i + 1; j < lines.length && !statements[j]; j++) statement += '\n' + lines[j];
797 if (!statement.includes(name)) continue;
798 const assignment = pythonAssignment(statement);
799 const assigned = assignment?.targets.some(t => target.test(t.trim())) ?? false;
800 if (!assigned && !dynamic.test(statement)) continue;
801 if (test) { out.writers.add(file); continue; }
802 // A write through an ambiguous spelling may land on another module: unknown.
803 const single = assignment && assignment.targets.length === 1 && !assignment.augmented && exact.test(assignment.targets[0]!.trim());
804 const value = single ? assignment!.value.trim() : '';
805 if (value === 'None') continue;
806 const constructor = value ? pythonConstructorCall(value) : null;
807 if (!constructor) { out.unknown = true; return out; }
808 out.writes.push({ type: constructor, file });
809 }
810 }
811 return out;
812 });
813}
814
815/**
816 * Whether the global's own module can write it through its namespace dict:

Callers 2

pythonGlobalClassesFunction · 0.85
pythonGlobalMembersFunction · 0.85

Calls 14

pythonNameScanFunction · 0.85
isPythonTestFileFunction · 0.85
pythonModuleAliasesFunction · 0.85
spellFunction · 0.85
pythonMemberLinesFunction · 0.85
pythonStatementStartsFunction · 0.85
pythonMainBlockLinesFunction · 0.85
pythonAssignmentFunction · 0.85
pythonConstructorCallFunction · 0.85
readFileMethod · 0.80
hasMethod · 0.80
addMethod · 0.80

Tested by

no test coverage detected