Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions punq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,13 @@ def _match_defaults(spec):
# Defaults for args are just a tuple. We match args with their defaults
# by position, starting at the first defaulted arg
offset = len(spec.args) - len(spec.defaults)
defaults = ([None] * offset) + list(spec.defaults)
defaults = ([empty] * offset) + list(spec.defaults)

ns = {key: value for key, value in zip(spec.args, defaults) if value is not None}
# filter only args with default value presented
ns = {key: value for key, value in zip(spec.args, defaults) if value is not empty}

if spec.kwonlydefaults is not None:
# defaults for kwargs are in a dict, so we just update the result dict.
# defaults for kwargs are in a dict, so we just update the result dict
ns.update(spec.kwonlydefaults)

return ns
Expand Down Expand Up @@ -491,7 +492,7 @@ def _build_impl(self, registration, resolution_args, context):

args = _match_defaults(spec)
args.update({
k: self._resolve_impl(v, resolution_args, context, args.get(k))
k: self._resolve_impl(v, resolution_args, context, args.get(k, empty))
for k, v in registration.needs.items()
if k != "return" and k not in registration.args and k not in resolution_args
})
Expand All @@ -516,7 +517,7 @@ def _should_auto_register(self, service_key, registration):
return False
return registration is None and inspect.isclass(service_key)

def _resolve_impl(self, service_key, kwargs, context, default=None):
def _resolve_impl(self, service_key, kwargs, context, default=empty):
context = self.registrations.build_context(service_key, context)

if service_key in self._singletons:
Expand All @@ -532,7 +533,7 @@ def _resolve_impl(self, service_key, kwargs, context, default=None):

registration = target.next_impl()

if registration is None and default is not None:
if registration is None and default is not empty:
return default

if self._should_auto_register(service_key, registration):
Expand Down
8 changes: 6 additions & 2 deletions tests/test_kwarg_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ class Dep:


class Client:
def __init__(self, a: Dep, b: int = 10):
def __init__(self, a: Dep, b: int = 10, c: str | None = None):
self.a = a
self.b = b
self.c = c


def test_can_create_instance_with_defaulted_kwarg():
Expand All @@ -20,6 +21,7 @@ def test_can_create_instance_with_defaulted_kwarg():

client = container.resolve(Client)
expect(client.b).to(equal(10))
expect(client.c).to(equal(None))


def test_defaults_are_superseded_by_registrations():
Expand All @@ -30,12 +32,14 @@ def test_defaults_are_superseded_by_registrations():

client = container.resolve(Client)
expect(client.b).to(equal(3))
expect(client.c).to(equal(None))


def test_defaults_are_superseded_by_context():
container = Container()
container.register(Dep)
container.register(Client)

client = container.resolve(Client, b=5)
client = container.resolve(Client, b=5, c="win")
expect(client.b).to(equal(5))
expect(client.c).to(equal("win"))