Skip to content

Do not type DeclarativeContainer.__getattr__ as returning a Provider (#910)#973

Open
uttam12331 wants to merge 1 commit into
ets-labs:masterfrom
uttam12331:fix/declarative-container-getattr-stub-910
Open

Do not type DeclarativeContainer.__getattr__ as returning a Provider (#910)#973
uttam12331 wants to merge 1 commit into
ets-labs:masterfrom
uttam12331:fix/declarative-container-getattr-stub-910

Conversation

@uttam12331

Copy link
Copy Markdown

Summary

Closes #910.

The container type stub declares

class Container:
    ...
    def __getattr__(self, name: str) -> Provider[Any]: ...

on the base Container, so DeclarativeContainer inherits a catch-all __getattr__. That makes type checkers accept access to any attribute on a declarative container as a Provider, silently hiding typos and references to providers that were never declared:

class Container(containers.DeclarativeContainer):
    service = providers.Factory(Service)

c = Container()
c.serivce  # typo — no type error today, inferred as Provider[Any]

As noted in the issue, this only makes sense for DynamicContainer, whose providers are added by name at runtime — not for DeclarativeContainer, whose providers are declared statically.

Change

Move the __getattr__ stub from the base Container to DynamicContainer. Now:

  • DeclarativeContainer exposes only its statically declared providers → accessing an undeclared attribute is flagged.
  • DynamicContainer keeps resolving arbitrary attributes to Provider[Any].

Verified with mypy --strict:

class C(containers.DeclarativeContainer):
    provider = providers.Factory(int)

C().provider       # ok: Factory[int]
C().nonexistent    # error: "C" has no attribute "nonexistent"   <-- previously silent

containers.DynamicContainer().anything   # ok: Provider[Any]

Tests

mypy --strict tests/typing passes (19 source files). Added Test 7 in tests/typing/dynamic_container.py asserting that dynamic attribute access still resolves to providers.Provider[Any], so the DynamicContainer behavior stays covered. The existing declarative_container.py typing tests continue to pass because they access explicitly declared providers.

The `__getattr__(self, name: str) -> Provider[Any]` stub lived on the base
`Container`, so `DeclarativeContainer` inherited a catch-all that made type
checkers accept access to any attribute — silencing typos and references to
providers that were never declared.

Move the stub to `DynamicContainer`, whose providers really are added by name
at runtime. `DeclarativeContainer` now only exposes its statically declared
providers, so accessing an undeclared one is flagged by the type checker while
dynamic containers keep resolving attributes to `Provider[Any]`.

Closes ets-labs#910
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.

__getattr__ typing silences legitimate issues

1 participant