Repository: jmwri/ioccontainer

Issue:
Inject should override value if None
When using the `@inject` decorator, the provided parameter should be overridden if it is `None`. At the moment the provider parameter takes precedence 100% of the time.

Discussion:

Patch:
diff --git a/ioccontainer/inject.py b/ioccontainer/inject.py
index 162f6e1..98ba622 100644
--- a/ioccontainer/inject.py
+++ b/ioccontainer/inject.py
@@ -50,7 +50,11 @@ def inject_decorator(container: 'Container'):
             service = container.get(cls)
 
             if _is_positional_argument(position, parameter, new_args):
-                new_args.append(service)
+                if len(new_args) >= position + 1:
+                    new_args[position] = service
+                else:
+                    new_args.append(service)
+
             elif _is_keyword_argument(parameter):
                 kwargs[parameter.name] = service
             else:
@@ -96,7 +100,9 @@ def _default_parameter_provided(parameter: inspect.Parameter) -> bool:
 
 def _argument_provided(position: int, parameter: inspect.Parameter,
                        args: typing.List, kwargs: typing.Dict) -> bool:
-    return position < len(args) or parameter.name in kwargs.keys()
+    if position < len(args) and args[position] is not None:
+        return True
+    return kwargs.get(parameter.name) is not None
 
 
 def _is_positional_argument(
@@ -106,7 +112,9 @@ def _is_positional_argument(
                         inspect.Parameter.POSITIONAL_OR_KEYWORD)
     if parameter.kind not in positional_types:
         return False
-    return position == len(args)
+    if position == len(args):
+        return True
+    return position + 1 == len(args) and args[position] is None
 
 
 def _is_keyword_argument(parameter: inspect.Parameter) -> bool:


Test patch:
diff --git a/tests/test_container.py b/tests/test_container.py
index d76d2e1..f338f75 100644
--- a/tests/test_container.py
+++ b/tests/test_container.py
@@ -148,3 +148,29 @@ def test_injection_to_constructor():
     my_class = MyClass('my_test_string')
     assert my_class.some_str is 'my_test_string'
     assert my_class.get_val() is 1
+
+
+@provider('str_service')
+def provide_str():
+    return 'string service'
+
+
+def test_param_overriding():
+    @inject(string='str_service')
+    def my_fn(string):
+        return string
+
+    assert my_fn() == 'string service'
+    assert my_fn('overridden') == 'overridden'
+    assert my_fn(None) == 'string service'
+
+
+def test_multiple_param_overriding():
+    @inject(s1='str_service', s2='str_service')
+    def my_fn(s1, s2):
+        return s1, s2
+
+    assert my_fn() == ('string service', 'string service')
+    assert my_fn('overridden') == ('overridden', 'string service')
+    assert my_fn(None) == ('string service', 'string service')
+    assert my_fn('overridden', None) == ('overridden', 'string service')