Support optional parameters #276
Open
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.
Overview
Support bindings for optional parameters.
Background
In application code some pieces of configuration can be considered optional. For example, consider an API server that supports authentication/authorization in staging and production, but can have this feature "turned off" for development by simply omitting the
auth
section of the server configuration.injector
already supports providers for optional types e.g.:In this example, I can easily set up an injector and get
AuthConfig | None
from the graph:When this is run it prints:
However, if I then write a provider function which requests
AuthConfig | None
as a dependency like:The injector raises indicating there is no provider for
Union[OAuth2Config, OidcConfig]
(type names shortened for brevity). Given theAuthConfig: TypeAlias = OAuth2Config | OidcConfig
alias from earlier this message implies something somewhere is requesting plainAuthConfig
as a dependency rather thanAuthConfig | None
, which has a provider in the graph.However, after combing my whole dependency graph I could not find a place where this was actually happening in my application code so I started digging further. After a lot of debugging I found that the function
_infer_injected_bindings
removesNoneType
from unions before resolving the rest of the injectable dependencies from a function signature:After removing the set difference operation from the assignment to
new_members
the code examples I share above start working instead of raising an exception about missing providers.Solution
The solution proposed here removes
- {type(None)}
fromnew_members = ...
to allow optional dependencies to be fulfilled if there is a provider configured for them.I also included a test to demonstrate the behavior in
test_get_bindings
. In the first commit the new test fails, but in the second commit with the proposed change applied it passes.This patch induces a change in the test for
test_get_bindings_for_pep_604
since nowa: int | None
resolves toint | None
instead of justint
.The rest of the test suite passes with this patch in place, so from what I can tell there aren't any unintended side effects on the rest of the codebase, but let me know if I'm missing something. Looking forward to getting your thoughts on this!