fix(pregate): linear Python string blanking, non-empty from-spec, repo-bounded depth

Second review round on the Python import scanner:

- An empty from-spec let the whitespace on both sides of it compete, so
  `from` followed by a long run of spaces backtracked quadratically. The
  spec now starts with a dot or a word character.
- Strings and comments are blanked by a single linear scanner that honours
  backslash escapes, so an escaped triple quote no longer ends a docstring
  early and swallows the imports after it.
- The fixed 32-segment cap dropped real deep modules. Dotted names are now
  bounded by the repo's deepest path, which no module can exceed.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-17 17:21:48 +00:00
1 parent b78fe8c597
commit f419c084b7
2 files changed
+49 -14

No files matched your search

+8 -4
View File
@@ -114,7 +114,7 @@ describe('import graph (static imports ∪ repo-path literals ∪ bin convention
]);
});
test('python: a package and a same-named module both map, statements after ; and : map, a path literal does not hide its patch target, and adversarial dotted input stays linear', () => {
test('python: a package and a same-named module both map, statements after ; and : map, escaped triple quotes and deep modules map, a path literal does not hide its patch target, and adversarial input stays linear', () => {
const repo = fixture();
commit(repo, {
'app.py': 'A = 1\n',
@@ -127,15 +127,19 @@ describe('import graph (static imports ∪ repo-path literals ∪ bin convention
'tests/test_semicolon.py': 'import os; import pkg.core\n',
'tests/test_inline.py': 'def test_core():\n if True: from pkg.core import C\n',
'tests/test_patch.py': "from unittest import mock\n\n@mock.patch('pkg.patched.Thing.run')\ndef test_run(run):\n pass\n",
'tests/test_adversarial.py': `from ${'.'.repeat(100_000)}x\nX = '${Array.from({ length: 20_000 }, () => 'pkg').join('.')}'\n`,
'tests/test_adversarial.py': `from ${'.'.repeat(100_000)}x\nfrom ${' '.repeat(100_000)}x\nX = '${Array.from({ length: 20_000 }, () => 'pkg').join('.')}'\n${'\\"""'.repeat(20_000)}\n`,
'tests/test_escaped.py': 'DOC = """text \\"""\nstill doc"""\nimport pkg.core\nTAIL = """x"""\n',
[`${Array.from({ length: 33 }, (_, i) => `d${i}`).join('/')}/leaf.py`]: 'L = 1\n',
'tests/test_deep.py': `import ${Array.from({ length: 33 }, (_, i) => `d${i}`).join('.')}.leaf\n`,
});
const g = buildGraph(repo.work);
expect(testsFor(g, 'app/__init__.py').tests).toEqual(['tests/test_app.py']);
expect(testsFor(g, 'app.py').tests).toEqual(['tests/test_app.py']);
expect(testsFor(g, 'pkg/core.py').tests).toEqual(['tests/test_inline.py', 'tests/test_semicolon.py']);
expect(testsFor(g, 'pkg/core.py').tests).toEqual(['tests/test_escaped.py', 'tests/test_inline.py', 'tests/test_semicolon.py']);
expect(testsFor(g, `${Array.from({ length: 33 }, (_, i) => `d${i}`).join('/')}/leaf.py`).tests).toEqual(['tests/test_deep.py']);
expect(testsFor(g, 'pkg/patched.py').tests).toEqual(['tests/test_patch.py']);
expect(testsFor(g, 'pkg.patched.Thing.run').tests).toEqual(['tests/test_patch.py']);
expect(testsFor(g, 'pkg/__init__.py').tests).toEqual(['tests/test_adversarial.py', 'tests/test_inline.py', 'tests/test_patch.py', 'tests/test_semicolon.py']);
expect(testsFor(g, 'pkg/__init__.py').tests).toEqual(['tests/test_adversarial.py', 'tests/test_escaped.py', 'tests/test_inline.py', 'tests/test_patch.py', 'tests/test_semicolon.py']);
});
});