Skip to content

fix(python): resolve a base class spelled through a root-binding import - #2679

Merged
DeusData merged 4 commits into
mainfrom
fix/py-dotted-base-qn
Oct 18, 2026
Merged

DeusData merged 4 commits into
mainfrom
fix/py-dotted-base-qn

Conversation

@DeusData

Copy link
Copy Markdown
Owner

What

import pkg.mod.nodes binds the ROOT name pkg, so class X(pkg.mod.nodes.Context) names module
pkg.mod.nodes's Context. The cross-LSP base resolution (pxc_resolve_base_qn) asked the registry,
whose import-map step joins the imported MODULE (the IMPORTS edge target, pkg.mod.nodes) with the whole
remaining spelling (mod.nodes.Context) and misses. The base kept its raw spelling, so the Python LSP's
inheritance view never saw it, and every member inherited through a dotted base fell to a name guess or
to nothing: self.m() became unique_name, super().m() suffix_match, and super().__init__() only
resolved through a synthesized QN.

pxc_resolve_base_qn now resolves such a spelling against the module the import names: the import
map's module when the root local is unique there, else the dotted module path under the project's QN
rule. Python only, import-backed and exact (no short-name step), and only a type-like project node is
accepted. import a.b as m and from a import b bind the module itself and keep resolving through the
import map. Import maps are not changed.

Evidence

Base origin/main 9f85f10 vs this head, 26 Python repos (manifest v1), production builds, macOS arm64,
--repeat 2, every repeat byte-identical.

base this PR +added -removed
CALLS 1,326,684 1,326,732 70 22
every other edge type except SEMANTICALLY_RELATED identical 0 0
scip-python, 23 repos: correct / answerable 410,551 / 436,028 410,621 / 436,076
scip-python recall (reference pairs found) 0.7967 0.7969
  • CALLS by strategy: +45 lsp_method, +25 lsp_super, -19 suffix_match, -3 same_module. Three repos
    change; the other 23 are identical:
    • mypy (+44/-7): class Type(mypy.nodes.Context) makes Instance.type -> TypeInfo methods
      resolvable; ASTStubGenerator(..., mypy.traverser.TraverserVisitor) and
      FreshenCallableVisitor(mypy.type_visitor.TypeTranslator) super() calls reach their base.
    • salt (+25/-15): classes such as class X(salt.utils.process.SignalHandlingProcess); super() and
      self. calls reach the right base methods (_handle_signals, __setstate__, fileclient.Client.*)
      instead of a same-module function, logmod.error, or a CI helper's ProxyClient.start.
    • mitmproxy (+1): super().__new__ through mitmproxy.hooks.Hook.
  • All changed edges were read: every addition is correct (MRO order for super()), every removal pointed
    at an overridden or unrelated definition. scip-python agrees exactly: +70 correct and +48 answerable
    (= 70 added - 22 removed), i.e. every added edge is a SCIP true positive and every removed one was a
    false positive.
  • SEMANTICALLY_RELATED moves (+23/-49) because that pass weights callee/caller names by a project-wide
    IDF; no change in its logic here.
  • Census (stdlib ast): 316 class bases spelled through a root-binding import on the corpus.

Tests

python_dotted_base_inheritance and ..._parallel (sequential and parallel venues): self.m(),
super().m() and super().__init__() through a dotted base resolve by the LSP; the from-imported
control keeps resolving; an untyped receiver stays without an LSP edge. GREEN here; with
pass_lsp_cross.c reverted to main both fail (dotted_self == 0). Affected suites (complexity,
registry, pipeline, cross_repo, py_lsp, py_lsp_stress, py_lsp_scale, lsp_resolution_probe,
incremental) pass on the merged tree. clang-format and cppcheck 2.20.0 clean on the changed file.

No index-format change: the fix only changes which project node a base spelling resolves to.

`import pkg.mod.nodes` binds the ROOT name `pkg`, so `class X(pkg.mod.nodes.Context)`
names module pkg.mod.nodes's Context. The cross-LSP base resolution asked
the registry, whose import_map step joined the imported MODULE (the
IMPORTS edge target, pkg.mod.nodes) with the whole remaining spelling
(mod.nodes.Context) and missed; the base kept its raw spelling, so the
Python LSP's inheritance view never saw it. Every member inherited through
a dotted base fell to a name guess or to nothing: self.m() became
unique_name, super().m() suffix_match, super().__init__() only resolved
through a synthesized QN.

pxc_resolve_base_qn now resolves such a spelling against the module the
import names: the import map's module when the root local is unique there,
else the dotted module path under the project's QN rule. Python only,
import-backed and exact (no short-name step), and only a type-like project
node is accepted. `import a.b as m` and `from a import b` bind the module
itself and keep resolving through the import map.

Tests: python_dotted_base_inheritance(_parallel): self.m(), super().m()
and super().__init__() through a dotted base resolve by the LSP; the
from-imported control keeps resolving; an untyped receiver stays without
an LSP edge.

Signed-off-by: Martin Vogel <[email protected]>
Whitespace only; the token stream is unchanged.

Signed-off-by: Martin Vogel <[email protected]>
yermakoffivan pushed a commit to yermakoffivan/codebase-memory-mcp that referenced this pull request Oct 18, 2026
…ONAL on every selection path

A runner suite registered only under a preprocessor condition (the four
coverage_* suites under `#if defined(CBM_TEST_COVERAGE) && !defined(_WIN32)`
in tests/test_main.c) is absent from builds without that condition. The
selection marked such a suite CONDITIONAL only on the per-registration path,
and only when a registration of its own was conditional and contributed a
reason. Every suite-level path (setup unknown or hit, suite-body, changed and
rule triggers, inventory, rejected artifact) made the suite whole without it,
and the runner registration's own condition was never recorded.

PR CI on the x86 Linux gcc leg then failed with "the test selection names
suites this build does not register: coverage_setup_success
coverage_setup_uncertain" (DeusData#2679, DeusData#2680): the suite-body trigger and an
incomplete setup row selected both suites whole without CONDITIONAL, so
selection.py left them out of optional-suites.txt.

The model now records whether a runner registration sits under a condition
(conditional only when every site of the suite is), and the selection marks
any selected conditionally registered suite whole with CONDITIONAL after every
whole-suite path. Unconditionally registered suites keep the strict contract.

Signed-off-by: Martin Vogel <[email protected]>
@DeusData
DeusData merged commit 5f66c86 into main Oct 18, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant