Hello community,

here is the log from the commit of package python-injector for openSUSE:Factory 
checked in at 2019-07-26 12:39:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-injector (Old)
 and      /work/SRC/openSUSE:Factory/.python-injector.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-injector"

Fri Jul 26 12:39:43 2019 rev:3 rq:718269 version:0.17.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-injector/python-injector.changes  
2019-06-12 13:17:32.572612599 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-injector.new.4126/python-injector.changes    
    2019-07-26 12:39:44.813929745 +0200
@@ -1,0 +2,15 @@
+Wed Jul 24 13:38:20 UTC 2019 - [email protected]
+
+- version update to 0.17.0
+  * Added support for using `typing.Dict` and `typing.List` in multibindings. 
See :meth:`multibind <injector.Binder.multibind>`.
+  * Added multibinding-specific :func:`provider <injector.provider>` variant: 
:func:`multiprovider <injector.multiprovider>`
+  * Deprecated using :func:`provider <injector.provider>` for multibindings
+  * Fixed failure to provide a default value to a `NewType`-aliased type with 
auto_bind enabled
+  * Deprecated :func:`Key <injector.Key>`, :func:`SequenceKey 
<injector.SequenceKey>` and
+    :func:`MappingKey <injector.MappingKey>` – use real types or type aliases 
instead
+  * Deprecated using single-item lists and dictionaries for multibindings - 
use real types or type aliases instead
+  Technically backwards incompatible:
+  * typing.List and typing.Dict specializations are now explicitly disallowed 
as :meth:`bind <injector.Binder.bind>`
+    interfaces and types returned by :func:`provider 
<injector.provider>`-decorated methods
+
+-------------------------------------------------------------------

Old:
----
  0.16.2.tar.gz

New:
----
  0.17.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-injector.spec ++++++
--- /var/tmp/diff_new_pack.CTJabc/_old  2019-07-26 12:39:45.281929472 +0200
+++ /var/tmp/diff_new_pack.CTJabc/_new  2019-07-26 12:39:45.285929470 +0200
@@ -19,7 +19,7 @@
 %define skip_python2 1
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-injector
-Version:        0.16.2
+Version:        0.17.0
 Release:        0
 Summary:        Python dependency injection framework, inspired by Guice
 License:        BSD-3-Clause
@@ -60,7 +60,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%python_exec setup.py test
+%pytest
 
 %files %{python_files}
 %license COPYING

++++++ 0.16.2.tar.gz -> 0.17.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.16.2/.gitignore 
new/injector-0.17.0/.gitignore
--- old/injector-0.16.2/.gitignore      2019-05-22 10:18:55.000000000 +0200
+++ new/injector-0.17.0/.gitignore      2019-06-15 16:23:44.000000000 +0200
@@ -6,3 +6,4 @@
 *,cover
 .mypy_cache/
 .pytest_cache/
+coverage.xml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.16.2/.travis.yml 
new/injector-0.17.0/.travis.yml
--- old/injector-0.16.2/.travis.yml     2019-05-22 10:18:55.000000000 +0200
+++ new/injector-0.17.0/.travis.yml     2019-06-15 16:23:44.000000000 +0200
@@ -6,16 +6,13 @@
   - "3.6"
   - "nightly"
   - "pypy3.5-5.8.0"
-env:
-  - TYPING_VERSION="<3.5.3"
-  - TYPING_VERSION=">=3.5.3"
 matrix:
   allow_failures:
     - python: "nightly"
   include:
     - { python: "3.7", dist: xenial, sudo: true }
 install:
-  - pip install --upgrade coveralls pytest "typing$TYPING_VERSION" 
"pytest-cov>=2.5.1" dataclasses
+  - pip install --upgrade coveralls pytest "pytest-cov>=2.5.1" dataclasses
   # mypy can't be installed on pypy
   - if [[ "${TRAVIS_PYTHON_VERSION}" != "pypy"* ]] ; then pip install mypy ; fi
   # Black is Python 3.6+-only
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.16.2/CHANGES new/injector-0.17.0/CHANGES
--- old/injector-0.16.2/CHANGES 2019-05-22 10:18:55.000000000 +0200
+++ new/injector-0.17.0/CHANGES 2019-06-15 16:23:44.000000000 +0200
@@ -1,6 +1,22 @@
 Injector Change Log
 ===================
 
+0.17.0
+------
+
+- Added support for using `typing.Dict` and `typing.List` in multibindings. 
See :meth:`multibind <injector.Binder.multibind>`.
+- Added multibinding-specific :func:`provider <injector.provider>` variant: 
:func:`multiprovider <injector.multiprovider>`
+- Deprecated using :func:`provider <injector.provider>` for multibindings
+- Fixed failure to provide a default value to a `NewType`-aliased type with 
auto_bind enabled
+- Deprecated :func:`Key <injector.Key>`, :func:`SequenceKey 
<injector.SequenceKey>` and
+  :func:`MappingKey <injector.MappingKey>` – use real types or type aliases 
instead
+- Deprecated using single-item lists and dictionaries for multibindings - use 
real types or type aliases instead
+
+Technically backwards incompatible:
+
+- typing.List and typing.Dict specializations are now explicitly disallowed as 
:meth:`bind <injector.Binder.bind>`
+  interfaces and types returned by :func:`provider 
<injector.provider>`-decorated methods
+
 0.16.2
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.16.2/README.md 
new/injector-0.17.0/README.md
--- old/injector-0.16.2/README.md       2019-05-22 10:18:55.000000000 +0200
+++ new/injector-0.17.0/README.md       2019-06-15 16:23:44.000000000 +0200
@@ -105,20 +105,22 @@
 
 ```
 
-Next, for the sake of the example, we'll create a "configuration" annotated 
type:
+Next, for the sake of the example, we'll create a configuration type:
 
 
 ```python
->>> Configuration = Key('configuration')
+>>> class Configuration:
+...     def __init__(self, connection_string):
+...         self.connection_string = connection_string
 
 ```
 
-Key is used to uniquely identify the configuration dictionary. Next, we bind 
the configuration to the injector, using a module:
+Next, we bind the configuration to the injector, using a module:
 
 
 ```python
 >>> def configure_for_testing(binder):
-...     configuration = {'db_connection_string': ':memory:'}
+...     configuration = Configuration(':memory:')
 ...     binder.bind(Configuration, to=configuration, scope=singleton)
 
 ```
@@ -131,7 +133,7 @@
 ...   @singleton
 ...   @provider
 ...   def provide_sqlite_connection(self, configuration: Configuration) -> 
sqlite3.Connection:
-...     conn = sqlite3.connect(configuration['db_connection_string'])
+...     conn = sqlite3.connect(configuration.connection_string)
 ...     cursor = conn.cursor()
 ...     cursor.execute('CREATE TABLE IF NOT EXISTS data (key PRIMARY KEY, 
value)')
 ...     cursor.execute('INSERT OR REPLACE INTO data VALUES ("hello", "world")')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.16.2/injector/__init__.py 
new/injector-0.17.0/injector/__init__.py
--- old/injector-0.16.2/injector/__init__.py    2019-05-22 10:18:55.000000000 
+0200
+++ new/injector-0.17.0/injector/__init__.py    2019-06-15 16:23:44.000000000 
+0200
@@ -21,15 +21,29 @@
 import sys
 import threading
 import types
+import warnings
 from abc import ABCMeta, abstractmethod
 from collections import namedtuple
-from typing import Any, Callable, cast, Dict, Generic, get_type_hints, List, 
Tuple, Type, TypeVar, Union
+from typing import (
+    Any,
+    Callable,
+    cast,
+    Dict,
+    Generic,
+    get_type_hints,
+    List,
+    overload,
+    Tuple,
+    Type,
+    TypeVar,
+    Union,
+)
 
 TYPING353 = hasattr(Union[str, int], '__origin__')
 
 
 __author__ = 'Alec Thomas <[email protected]>'
-__version__ = '0.16.2'
+__version__ = '0.17.0'
 __version_tag__ = ''
 
 log = logging.getLogger('injector')
@@ -39,6 +53,8 @@
     log.setLevel(logging.WARN)
 
 T = TypeVar('T')
+K = TypeVar('K')
+V = TypeVar('V')
 
 
 def private(something: T) -> T:
@@ -250,10 +266,20 @@
         if isinstance(what, list):
             if len(what) != 1:
                 raise Error('list bindings must have a single interface ' 
'element')
+            warnings.warn(
+                'Multibinding using the %s form is deprecated, use typing.List 
instead.' % (what,),
+                RuntimeWarning,
+                stacklevel=3,
+            )
             what = (list, BindingKey.create(what[0]))
         elif isinstance(what, dict):
             if len(what) != 1:
                 raise Error('dictionary bindings must have a single interface 
' 'key and value')
+            warnings.warn(
+                'Multibinding using the %s form is deprecated, use typing.Dict 
instead.' % (what,),
+                RuntimeWarning,
+                stacklevel=3,
+            )
             what = (dict, BindingKey.create(list(what.items())[0]))
         return tuple.__new__(cls, (what,))
 
@@ -269,6 +295,9 @@
 class Binding(_BindingBase):
     """A binding from an (interface,) to a provider in a scope."""
 
+    def is_multibinding(self) -> bool:
+        return _get_origin(_punch_through_alias(self.interface)) in {dict, 
list}
+
 
 class Binder:
     """Bind interfaces to implementations.
@@ -293,6 +322,11 @@
     def bind(self, interface, to=None, scope=None):
         """Bind an interface to an implementation.
 
+        `typing.List` and `typing.Dict` instances are reserved for 
multibindings and trying to bind them
+        here will result in an error (use :meth:`multibind` instead)::
+
+            binder.bind(List[str], to=['hello', 'there'])  # Error
+
         :param interface: Interface or :func:`Key` to bind.
         :param to: Instance or class to bind to, or an explicit
              :class:`Provider` subclass.
@@ -300,23 +334,71 @@
         """
         if type(interface) is type and issubclass(interface, (BaseMappingKey, 
BaseSequenceKey)):
             return self.multibind(interface, to, scope=scope)
+        if _get_origin(_punch_through_alias(interface)) in {dict, list}:
+            raise Error(
+                'Type %s is reserved for multibindings. Use multibind instead 
of bind.' % (interface,)
+            )
         key = BindingKey.create(interface)
         self._bindings[key] = self.create_binding(interface, to, scope)
 
+    @overload
+    def multibind(
+        self,
+        interface: Union['BaseSequenceKey', 'BaseMappingKey'],
+        to: Any,
+        scope: Union[Type['Scope'], 'ScopeDecorator'] = None,
+    ) -> None:
+        pass
+
+    @overload
+    def multibind(
+        self,
+        interface: Type[List[T]],
+        to: Union[List[T], Callable[..., List[T]], Provider[List[T]]],
+        scope: Union[Type['Scope'], 'ScopeDecorator'] = None,
+    ) -> None:
+        pass
+
+    @overload
+    def multibind(
+        self,
+        interface: Type[Dict[K, V]],
+        to: Union[Dict[K, V], Callable[..., Dict[K, V]], Provider[Dict[K, V]]],
+        scope: Union[Type['Scope'], 'ScopeDecorator'] = None,
+    ) -> None:
+        pass
+
     def multibind(self, interface, to, scope=None):
         """Creates or extends a multi-binding.
 
-        A multi-binding maps from a key to a sequence, where each element in
-        the sequence is provided separately.
+        A multi-binding contributes values to a list or to a dictionary. For 
example::
 
-        :param interface: :func:`MappingKey` or :func:`SequenceKey` to bind to.
+            binder.multibind(List[str], to=['some', 'strings'])
+            binder.multibind(List[str], to=['other', 'strings'])
+            injector.get(List[str])  # ['some', 'strings', 'other', 'strings']
+
+            binder.multibind(Dict[str, int], to={'key': 11})
+            binder.multibind(Dict[str, int], to={'other_key': 33})
+            injector.get(Dict[str, int])  # {'key': 11, 'other_key': 33}
+
+        .. versionchanged:: 0.17.0
+            Added support for using `typing.Dict` and `typing.List` instances 
as interfaces.
+            Deprecated support for `MappingKey`, `SequenceKey` and single-item 
lists and
+            dictionaries as interfaces.
+
+        :param interface: :func:`MappingKey`, :func:`SequenceKey` or 
typing.Dict or typing.List instance to bind to.
         :param to: Instance, class to bind to, or an explicit :class:`Provider`
-                subclass. Must provide a sequence.
+                subclass. Must provide a list or a dictionary, depending on 
the interface.
         :param scope: Optional Scope in which to bind.
         """
         key = BindingKey.create(interface)
         if key not in self._bindings:
-            if isinstance(interface, dict) or isinstance(interface, type) and 
issubclass(interface, dict):
+            if (
+                isinstance(interface, dict)
+                or isinstance(interface, type)
+                and issubclass(interface, dict)
+                or _get_origin(_punch_through_alias(interface)) is dict
+            ):
                 provider = MapBindProvider()
             else:
                 provider = MultiBindProvider()
@@ -373,10 +455,8 @@
         return Binding(interface, provider, scope)
 
     def provider_for(self, interface, to=None):
-        if getattr(interface, '__qualname__', '') == 
'NewType.<locals>.new_type':
-            base_type = interface.__supertype__
-        else:
-            base_type = interface
+        base_type = _punch_through_alias(interface)
+        origin = _get_origin(base_type)
 
         if interface is Any:
             raise TypeError('Injecting Any is not supported')
@@ -411,15 +491,20 @@
             (target,) = interface.__args__
             builder = interface(self.injector, target)
             return InstanceProvider(builder)
-        elif isinstance(base_type, (tuple, type)) and interface is not Any and 
isinstance(to, base_type):
+        elif (
+            origin is None
+            and isinstance(base_type, (tuple, type))
+            and interface is not Any
+            and isinstance(to, base_type)
+            or origin in {dict, list}
+            and isinstance(to, origin)
+        ):
             return InstanceProvider(to)
-        elif issubclass(type(interface), type) or isinstance(interface, 
(tuple, list)):
+        elif issubclass(type(base_type), type) or isinstance(base_type, 
(tuple, list)):
             if to is not None:
                 return InstanceProvider(to)
-            return ClassProvider(interface)
+            return ClassProvider(base_type)
 
-        elif hasattr(interface, '__call__'):
-            raise TypeError('Injecting partially applied functions is no 
longer supported.')
         else:
             raise UnknownProvider('couldn\'t determine provider for %r to %r' 
% (interface, to))
 
@@ -432,7 +517,7 @@
 
         raise KeyError
 
-    def get_binding(self, cls, key):
+    def get_binding(self, key):
         is_scope = isinstance(key.interface, type) and 
issubclass(key.interface, Scope)
         try:
             return self._get_binding(key, only_this_binder=is_scope)
@@ -448,7 +533,7 @@
                 self._bindings[key] = binding
                 return binding, self
 
-        raise UnsatisfiedRequirement(cls, key)
+        raise UnsatisfiedRequirement(key)
 
     def _is_special_interface(self, interface):
         # "Special" interfaces are ones that you cannot bind yourself but
@@ -483,6 +568,23 @@
         return isinstance(cls, type) and cls is not Any and issubclass(cls, 
generic_class)
 
 
+def _punch_through_alias(type_: Any) -> type:
+    if getattr(type_, '__qualname__', '') == 'NewType.<locals>.new_type':
+        return type_.__supertype__
+    else:
+        return type_
+
+
+def _get_origin(type_: type) -> type:
+    origin = getattr(type_, '__origin__', None)
+    # Older typing behaves differently there and stores Dict and List as 
origin, we need to be flexible.
+    if origin is List:
+        return list
+    elif origin is Dict:
+        return dict
+    return origin
+
+
 class Scope:
     """A Scope looks up the Provider for a binding.
 
@@ -598,7 +700,8 @@
             binding = None
             if hasattr(function, '__binding__'):
                 binding = function.__binding__
-                binder.bind(
+                bind_method = binder.multibind if binding.is_multibinding() 
else binder.bind
+                bind_method(
                     binding.interface, to=types.MethodType(binding.provider, 
self), scope=binding.scope
                 )
         self.configure(binder)
@@ -684,13 +787,13 @@
         :returns: An implementation of interface.
         """
         key = BindingKey.create(interface)
-        binding, binder = self.binder.get_binding(None, key)
+        binding, binder = self.binder.get_binding(key)
         scope = scope or binding.scope
         if isinstance(scope, ScopeDecorator):
             scope = scope.scope
         # Fetch the corresponding Scope instance from the Binder.
         scope_key = BindingKey.create(scope)
-        scope_binding, _ = binder.get_binding(None, scope_key)
+        scope_binding, _ = binder.get_binding(scope_key)
         scope_instance = scope_binding.provider.get(self)
 
         log.debug(
@@ -892,11 +995,42 @@
     >>> injector.get(str)
     '654'
     """
+    _mark_provider_function(function, allow_multi=False)
+    return function
+
+
+def multiprovider(function: CallableT) -> CallableT:
+    """Like :func:`provider`, but for multibindings. Example usage::
+
+        class MyModule(Module):
+            @multiprovider
+            def provide_strs(self) -> List[str]:
+                return ['str1']
+
+        class OtherModule(Module):
+            @multiprovider
+            def provide_strs_also(self) -> List[str]:
+                return ['str2']
+
+        Injector([MyModule, OtherModule]).get(List[str])  # ['str1', 'str2']
+
+    See also: :meth:`Binder.multibind`."""
+    _mark_provider_function(function, allow_multi=True)
+    return function
+
+
+def _mark_provider_function(function: Callable, *, allow_multi: bool) -> None:
     scope_ = getattr(function, '__scope__', None)
     annotations = inspect.getfullargspec(function).annotations
     return_type = annotations['return']
-    function.__binding__ = Binding(return_type, inject(function), scope_)
-    return function
+    origin = _get_origin(_punch_through_alias(return_type))
+    if origin in {dict, list} and not allow_multi:
+        raise Error(
+            'Function %s needs to be decorated with multiprovider instead of 
provider if it is to '
+            'provide values to a multibinding of type %s' % 
(function.__name__, return_type)
+        )
+    binding = Binding(return_type, inject(function), scope_)
+    function.__binding__ = binding  # type: ignore
 
 
 def inject(constructor_or_class):
@@ -1030,12 +1164,16 @@
 def Key(name: str) -> BaseKey:
     """Create a new type key.
 
+    .. versionchanged:: 0.17.0
+        Deprecated, use `typing.NewType` with a real type or subclass a real 
type instead.
+
     >>> Age = Key('Age')
     >>> def configure(binder):
     ...   binder.bind(Age, to=90)
     >>> Injector(configure).get(Age)
     90
     """
+    warnings.warn('Key is deprecated, use a real type instead', 
RuntimeWarning, stacklevel=3)
     return cast(BaseKey, type(name, (BaseKey,), {}))
 
 
@@ -1051,7 +1189,12 @@
 
 
 def MappingKey(name: str) -> BaseMappingKey:
-    """As for Key, but declares a multibind mapping."""
+    """As for Key, but declares a multibind mapping.
+
+    .. versionchanged:: 0.17.0
+        Deprecated, use `typing.Dict` instance instead.
+    """
+    warnings.warn('SequenceKey is deprecated, use typing.Dict instead', 
RuntimeWarning, stacklevel=3)
     return cast(BaseMappingKey, type(name, (BaseMappingKey,), {}))
 
 
@@ -1067,7 +1210,12 @@
 
 
 def SequenceKey(name: str) -> BaseSequenceKey:
-    """As for Key, but declares a multibind sequence."""
+    """As for Key, but declares a multibind sequence.
+
+    .. versionchanged:: 0.17.0
+        Deprecated, use `typing.List` instance instead.
+    """
+    warnings.warn('SequenceKey is deprecated, use typing.List instead', 
RuntimeWarning, stacklevel=3)
     return cast(BaseSequenceKey, type(name, (BaseSequenceKey,), {}))
 
 
@@ -1106,7 +1254,7 @@
     def build(self, **kwargs: Any) -> T:
         key = BindingKey.create(self._target)
         binder = self._injector.binder
-        binding, _ = binder.get_binding(None, key)
+        binding, _ = binder.get_binding(key)
         provider = binding.provider
         if not isinstance(provider, ClassProvider):
             raise Error(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.16.2/injector_test.py 
new/injector-0.17.0/injector_test.py
--- old/injector-0.16.2/injector_test.py        2019-05-22 10:18:55.000000000 
+0200
+++ new/injector-0.17.0/injector_test.py        2019-06-15 16:23:44.000000000 
+0200
@@ -18,6 +18,8 @@
 import traceback
 import warnings
 
+from typing import Dict, List, NewType
+
 import pytest
 
 from injector import (
@@ -28,6 +30,7 @@
     InstanceProvider,
     ClassProvider,
     inject,
+    multiprovider,
     noninjectable,
     singleton,
     threadlocal,
@@ -522,7 +525,7 @@
     assert Injector(MyModule()).get(str) == 'Bob is 25 and weighs 50.0kg'
 
 
-def test_multibind():
+def test_multibind_old():
     Names = Key('names')
 
     def configure_one(binder):
@@ -534,6 +537,103 @@
     assert Injector([configure_one, configure_two]).get(Names) == ['Bob', 
'Tom']
 
 
+def test_multibind():
+    Names = NewType('Names', List[str])
+    Passwords = NewType('Ages', Dict[str, str])
+
+    # First let's have some explicit multibindings
+    def configure(binder):
+        binder.multibind(List[str], to=['not a name'])
+        binder.multibind(Dict[str, str], to={'asd': 'qwe'})
+        # To make sure Lists and Dicts of different subtypes are treated 
distinctly
+        binder.multibind(List[int], to=[1, 2, 3])
+        binder.multibind(Dict[str, int], to={'weight': 12})
+        # To see that NewTypes are treated distinctly
+        binder.multibind(Names, to=['Bob'])
+        binder.multibind(Passwords, to={'Bob': 'password1'})
+
+    # Then @multiprovider-decorated Module methods
+    class CustomModule(Module):
+        @multiprovider
+        def provide_some_ints(self) -> List[int]:
+            return [4, 5, 6]
+
+        @multiprovider
+        def provide_some_strs(self) -> List[str]:
+            return ['not a name either']
+
+        @multiprovider
+        def provide_str_to_str_mapping(self) -> Dict[str, str]:
+            return {'xxx': 'yyy'}
+
+        @multiprovider
+        def provide_str_to_int_mapping(self) -> Dict[str, int]:
+            return {'height': 33}
+
+        @multiprovider
+        def provide_names(self) -> Names:
+            return ['Alice', 'Clarice']
+
+        @multiprovider
+        def provide_passwords(self) -> Passwords:
+            return {'Alice': 'aojrioeg3', 'Clarice': 'clarice30'}
+
+    injector = Injector([configure, CustomModule])
+    assert injector.get(List[str]) == ['not a name', 'not a name either']
+    assert injector.get(List[int]) == [1, 2, 3, 4, 5, 6]
+    assert injector.get(Dict[str, str]) == {'asd': 'qwe', 'xxx': 'yyy'}
+    assert injector.get(Dict[str, int]) == {'weight': 12, 'height': 33}
+    assert injector.get(Names) == ['Bob', 'Alice', 'Clarice']
+    assert injector.get(Passwords) == {'Bob': 'password1', 'Alice': 
'aojrioeg3', 'Clarice': 'clarice30'}
+
+
+def test_regular_bind_and_provider_dont_work_with_multibind():
+    # We only want multibind and multiprovider to work to avoid confusion
+
+    Names = NewType('Names', List[str])
+    Passwords = NewType('Passwords', Dict[str, str])
+
+    class MyModule(Module):
+        with pytest.raises(Error):
+
+            @provider
+            def provide_strs(self) -> List[str]:
+                return []
+
+        with pytest.raises(Error):
+
+            @provider
+            def provide_names(self) -> Names:
+                return []
+
+        with pytest.raises(Error):
+
+            @provider
+            def provide_strs_in_dict(self) -> Dict[str, str]:
+                return {}
+
+        with pytest.raises(Error):
+
+            @provider
+            def provide_passwords(self) -> Passwords:
+                return {}
+
+    injector = Injector()
+    binder = injector.binder
+
+    with pytest.raises(Error):
+        binder.bind(List[str], to=[])
+
+    with pytest.raises(Error):
+        binder.bind(Names, to=[])
+
+    with pytest.raises(Error):
+        binder.bind(Dict[str, str], to={})
+
+    with pytest.raises(Error):
+        binder.bind(Passwords, to={})
+
+
 def test_provider_sequence_decorator():
     Names = SequenceKey('names')
 
@@ -557,6 +657,16 @@
     assert isinstance(injector.get(A), A)
 
 
+def test_auto_bind_with_newtype():
+    # Reported in https://github.com/alecthomas/injector/issues/117
+    class A:
+        pass
+
+    AliasOfA = NewType('AliasOfA', A)
+    injector = Injector()
+    assert isinstance(injector.get(AliasOfA), A)
+
+
 def test_custom_scope():
     class RequestScope(Scope):
         def configure(self):


Reply via email to