Repository navigation
Keep the base module providers on a subclass - #331
Merged
Merged
Conversation
Contributor
A Module subclass rebuilt its provider list from its own attributes, so inheriting a module dropped everything the base defined. A subclass that redefines a provider now replaces it instead of registering both. is_provided read the attribute through inheritance, so an undecorated subclass of a provided class counted as provided and got scanned and registered. It now reads the class's own __dict__.
antonrh
force-pushed
the
fix-module-inheritance
branch
from
August 31, 2026 07:46
80c78a3 to
8bfe9fd
Compare
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.
Two bugs about inheritance, one in modules and one in the
@singletonfamily.A module subclass lost its base providers
ModuleMeta.__new__collectedprovidersfromattrs, the attributes of theclass being defined, so a subclass kept only what it declared itself:
The metaclass now starts from the bases and applies the class's own providers
on top. The collection is keyed by name, so a subclass that redefines a
provider replaces it instead of the module registering both, and an earlier
base wins over a later one, the way the MRO resolves an attribute.
An undecorated subclass counted as provided
is_providedread__provided__withhasattr, and the attribute isinherited, so every subclass of a provided class looked provided. The whole
metadata came with it, including the keys that belong to one class only.
An inherited
aliasregisters the same interface twice:An inherited
from_contextclaims a registration nobody made:And
container.scan()registered every subclass it walked past, whether ornot anyone meant it to be a dependency.
is_providednow reads the class's own__dict__, the way_check_already_providedalready did. Decorating a subclass of a providedclass still works, and a test covers it.
This changes behaviour. A subclass that used to resolve by inheriting the
base's scope now raises
LookupErrornaming the class and saying to decorateit. Marking the class, or its own
__provided__, is the fix. The pattern thedocumentation shows, an undecorated base with the decorated class aliased to
it, is unaffected.
is_providernext to it stays onhasattron purpose: providers are methods,and a subclass inheriting one is exactly what the first fix needs.