Repository navigation
Conversation
_get_base_class only resolved base-class names via module globals, never the calling frame's locals. For a nested class body (class Foo: class Bar: ...; class Car(Bar): ...), Bar exists only as a local variable in the enclosing Foo class body's execution frame, so resolution fell through to a builtins lookup and raised AttributeError. Thread the calling frame's f_locals into _get_base_classes/_get_base_class and check it before globals (locals shadow globals per normal Python scoping), fixing the nested case while preserving the existing top-level behavior. Fixes mkorpela#86
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.
Summary
Captured the calling frame in _overrides (sys._getframe(3)) and passed its f_locals through _get_base_classes into _get_base_class as a new local_vars parameter. _get_base_class now checks local_vars first (when the component name is present there) before falling back to the existing namespace (globals) lookup, matching normal Python scoping where locals shadow globals. This resolves nested/sibling class names correctly while leaving the existing top-level-class resolution path (which relies on globals) unchanged since local_vars simply won't contain those names.
Problem
mkorpela/overrides issue reference: #86
Root Cause
_overrides() resolves base-class names found via bytecode disassembly (_get_base_class_names) through _get_base_class(components, namespace), where namespace is only the module's global_vars (method.globals or vars(sys.modules[...])). It never consults the calling frame's f_locals. For a nested class body, the sibling class name (Bar) exists only as a local variable in the enclosing class's (Foo's) execution frame — it's never a module global — so lookup falls through to the builtins fallback, which naturally doesn't have it either, raising AttributeError.
Testing
PASS - all 70 tests in the suite pass, including the 2 new regression tests (one asserting the nested-sibling-class override works and returns the correct value, one asserting an incompatible override in the same nested scenario still correctly raises TypeError).
Related Issue
#86