Skip to content

Fix false dependency from a class to a same-named outer constant#45

Merged
bboe merged 1 commit into
mainfrom
fix-constant-class-dependency
Jun 15, 2026
Merged

Fix false dependency from a class to a same-named outer constant#45
bboe merged 1 commit into
mainfrom
fix-constant-class-dependency

Conversation

@bboe

@bboe bboe commented Jun 15, 2026

Copy link
Copy Markdown
Member

Found while rolling codesorter out to bboe/update_checker, whose core.py import broke with a NameError.

The bug

An enum member (or class variable) named like the module constant that aliases it:

class _Sentinel(Enum):
    CACHE_MISS = auto()

CACHE_MISS = _Sentinel.CACHE_MISS   # codesorter hoisted this ABOVE the class -> NameError

_get_dependencies(_Sentinel) matched the class-body binding CACHE_MISS and resolved it to the module-level constant, forging a false _Sentinel -> CACHE_MISS edge. Combined with the real CACHE_MISS -> _Sentinel edge that is a cycle, and cycle-breaking releases the lowest-keyed node (the constant) first — hoisting it above the class it references.

The fix

A name bound at a class's own body level belongs to that class's namespace, so it imposes no ordering on an outer definition of the same name. The guard is scoped to name_scope.node == node so a name bound in the enclosing class (a sibling method that an alias = method assignment references) is still a real dependency — test_alias_function covers that and stays green.

Verification

  • New regression fixture enum_member_alias + test_enum_member_alias; full suite (28) green, pyright clean.
  • Ran the fixed codesorter across all six bboe rollout repos (update_checker, sbmod, reclaude, deslackify, flask-image-uploader, extended_http_server): every one sorts to valid syntax and is F821 (undefined-name) clean. update_checker now orders _Sentinel before CACHE_MISS and its 42 tests pass. No other rollout-breaking issues surfaced.

@bboe bboe force-pushed the fix-constant-class-dependency branch 2 times, most recently from 5ed544b to 2500b3d Compare June 15, 2026 00:11
…definition

An enum member or class variable named like the module constant that aliases
it forged a false class->constant edge, closing a cycle that hoisted the
constant above the class it references (NameError at import). A name bound in
a class's own body is now recognized as that class's own namespace and imposes
no ordering on outer definitions.

Also make every test_files fixture self-contained and side-effect free, and
replace the parse-only guard with test_fixture_files_execute, which runs each
input and output file in a fresh namespace. This catches a fixture that parses
but does not run -- exactly the failure mode of an unsorted input or a codemod
output that hoists a definition above one it depends on. Six fixtures that
referenced undefined names or mutated global state (sys.path, __file__) were
rewritten to valid, runnable equivalents and their outputs regenerated.
@bboe bboe force-pushed the fix-constant-class-dependency branch from 2500b3d to 981e04f Compare June 15, 2026 00:23
@bboe bboe merged commit 25665b1 into main Jun 15, 2026
9 checks passed
@bboe bboe deleted the fix-constant-class-dependency branch June 15, 2026 00:40
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