Repository navigation
Conversation
Most used-name keys in a module are plain usages with no definitions. _AbstractUsedNamesFilter.values() still ran _get_definition_names() and ParserTreeFilter._filter() for each of them, only to get an empty list. Look up the per-module definition cache once in values() and skip keys without definitions. Return early from _filter() for empty input, check until_position and reachability in one pass, and sort in _check_flows() only when there are two or more names. Results and their order are unchanged. Completion benchmark (9 stdlib modules plus Interpreter completions): 462.7 ms -> 419.4 ms. Co-Authored-By: Aiden <aiden@weco.ai>
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.
TL;DR
ParserTreeFilter.values()andParserTreeFilter._filterfaster, so name completion gets faster.values()now skips name keys that have no definitions and looks up the module cache once.Interpretercompletions): 462.7 ms -> 419.4 ms, 9.4% faster.pytest test/shows the same 44 failures asmaster(environment-dependent), 3883 passed.What & Why
Most keys in
used_namesare plain usages, not definitions. Before,values()still called_get_definition_names()and_filter()for each of these keys. Each call did a weak dict lookup, asuper()call, two list builds and a generator, only to return an empty list.Now
values()gets the per-module definition cache once. Then it skips keys whose definition tuple is empty._filter()returns early for empty input and checksuntil_positionand reachability in one list comprehension._check_flows()sorts only when there are two or more names, and it returns a list.The output stays identical. Every
_filter()override (ClassFilter,SelfAttributeFilter,FixtureFilter,StubFilter) returns nothing for empty input. The cache keeps the same keys and values. Names keep the same order. The flow checks run in the same order and stop at the same name.Changes
_AbstractUsedNamesFilter.values(): get the definition cache once, fill it in the same way, and skip empty keys.ParserTreeFilter._filter(): return early for no names; use one list comprehension; nosuper()call.ParserTreeFilter._check_flows(): sort only for two or more names; build and return a list.Results
Median times on one dedicated CPU core, Python 3.12,
InterpreterEnvironment.Interpretercompletions)Script.complete()at end ofargparse.pyScript.complete()at end ofbisect.pyInterpretercompletions (C,C.foo,C.,os.path.)Interpreter("str.").complete()Script.infer()on one local name (does not usevalues())Why this is safe and easy to maintain
The change is small and stays in
jedi/inference/filters.py. It keeps the same structure and only removes extra work. The completion results, their order and the cache contents do not change.test/test_api/test_interpreter.py,test_classes.py,test_signature.py,test_imports.pyand the completion integration tests cover this code.Validation
pytest test/test_api/test_interpreter.py test/test_inference/test_signature.py test/test_api/test_classes.py test/test_inference/test_imports.py: 485 passed, 5 skipped, 4 xfailed (same asmaster).pytest test/: 44 failed, 3883 passed, 111 skipped, 5 xfailed. The 44 failures are the same test IDs onmaster(environment-dependenttest_integrationpytest/conftest cases andtest_namespace_package.py::test_relative_import).complete,name_with_symbols, order).AI assistance
Codex (gpt-6.1-sol) generated the candidate changes, and Weco Observe tracked and benchmarked them. Claude Code selected this candidate and ran the tests and benchmarks above. It also rejected a faster candidate because it crashed on empty modules.
Weco share link: https://dashboard.weco.ai/share/FvOQKGvG0Xt8f_28B1bRfiP_tq4kRO_z