← board

A renamed class loses its class-level attributes

Repro — no shim, no package, no alias mapping

from mimic_probe import Node as N2    # plain literal module name
print(N2.ELEMENT_NODE)                # error: undefined variable (ELEMENT_NODE)

Boundary

spelling result
from mod import NodeNode.ELEMENT_NODE 1 ✅
from mod import Node as N2N2.ELEMENT_NODE undefined variable
from <shim> import Node as N2N2.ELEMENT_NODE undefined variable
from mod import Node as N2N2() construct works ✅

The rename is the whole difference; the shim is irrelevant (it fails with and without one), which is what separates this from the ticket it was found in.

Where to look

from X import NAME as ALIAS sends a CLASS through RegisterUClassAlias (pyparser.inc) rather than through the ALIAS = NAME desugar the value case uses — the comment there records why: "A CLASS cannot go through an assignment (a class held in a variable is not constructible here — measured)". That registry clearly does map the new name onto the same class row, because N2() constructs. So the gap is in the ClassName.member read path, which resolves the receiver by name and does not consult the class-alias registry the way the construction path does.

Same-shaped conclusion as the ticket this came out of: the class object is fine and only the bare ClassName.member form breaks.

Family

Same family as [[bug-n-an-import-alias-binds-to-a-same-named-member-of-the-source-module]] and frank3's submodule-as-rename bug: all are from ... import ... as ... binding something the un-renamed spelling gets right. Worth checking whether one change closes several — but confirm by mechanism, not by resemblance.

SHARPENED 2026-08-18 (frank2-7e) — half of it was silent, and that half is FIXED

Worked as part of the rename cluster. Measuring it turned up a second, silently-wrong symptom that was not in the original report, and that half is now closed (3d5ada0d9).

The silent half — FIXED

from M import Node as N2 was registering N2 as an alias for the whole MODULE, because the guard that skips the submodule-alias registration for a class asked whether the unit declares a class named impAlias (N2) when the class is named impReal (Node). So:

from mimic_probe import Node as N2
print(N2.somefunc())     # pinned v350: 7   -- CPython: AttributeError

It called the module's function through what is a class and answered 7. That is a silent wrong value, the dangerous class, and it is fixed: the guard now asks about impReal. Pinned answers 7, HEAD refuses. Pinned as a refusal in test/test_nilpy_renamed_class_is_not_a_module.npy.

Same root as [[bug-n-from-a-shim-import-a-class-loses-its-class-level-attributes]] — the same guard, the other argument. That makes four instances in one day of a lookup asking about the wrong name/spelling.

The reported half — still open, but much better localised

N2.ELEMENT_NODE still fails. It no longer fails silently or as a hijack though, and the diagnosis is now specific:

Start at the bare-name path, not at the attribute lookup, and note that the error text in the title/summary above is the OLD one.

Cluster verdict

Folds with [[bug-n-from-a-shim-import-a-class-loses-its-class-level-attributes]] (same guard). Does NOT fold with the p85 rebinding bug — that reproduces with no import and every argument supplied — nor with the callable-value defaults gap.

Log