Hello community,

here is the log from the commit of package python-injector for openSUSE:Factory 
checked in at 2019-12-11 12:15:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-injector (Old)
 and      /work/SRC/openSUSE:Factory/.python-injector.new.4691 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-injector"

Wed Dec 11 12:15:00 2019 rev:4 rq:755754 version:0.18.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-injector/python-injector.changes  
2019-07-26 12:39:44.813929745 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-injector.new.4691/python-injector.changes    
    2019-12-11 12:15:19.276508220 +0100
@@ -1,0 +2,7 @@
+Wed Dec 11 08:48:54 UTC 2019 - Tomáš Chvátal <tchva...@suse.com>
+
+- Update to 0.18.1:
+  * Various minor fixes and support for new python
+- Depend on full python interpreter for sqlite module
+
+-------------------------------------------------------------------

Old:
----
  0.17.0.tar.gz

New:
----
  0.18.1.tar.gz

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

Other differences:
------------------
++++++ python-injector.spec ++++++
--- /var/tmp/diff_new_pack.wX86H5/_old  2019-12-11 12:15:19.792508074 +0100
+++ /var/tmp/diff_new_pack.wX86H5/_new  2019-12-11 12:15:19.792508074 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-injector
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,18 +19,20 @@
 %define skip_python2 1
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-injector
-Version:        0.17.0
+Version:        0.18.1
 Release:        0
 Summary:        Python dependency injection framework, inspired by Guice
 License:        BSD-3-Clause
-Group:          Development/Languages/Python
 URL:            https://github.com/alecthomas/injector
 Source:         
https://github.com/alecthomas/injector/archive/%{version}.tar.gz
-BuildRequires:  %{python_module pytest-cov}
 BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module typing_extensions >= 3.7.4}
+BuildRequires:  %{pythons}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
+Requires:       python
+Requires:       python-typing_extensions >= 3.7.4
 BuildArch:      noarch
 %python_subpackages
 
@@ -51,6 +53,7 @@
 
 %prep
 %setup -q -n injector-%{version}
+rm pytest.ini
 
 %build
 %python_build

++++++ 0.17.0.tar.gz -> 0.18.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/.travis.yml 
new/injector-0.18.1/.travis.yml
--- old/injector-0.17.0/.travis.yml     2019-06-15 16:23:44.000000000 +0200
+++ new/injector-0.18.1/.travis.yml     2019-12-10 02:25:28.000000000 +0100
@@ -4,15 +4,16 @@
 python:
   - "3.5"
   - "3.6"
+  - "3.7"
+  - "3.8"
   - "nightly"
-  - "pypy3.5-5.8.0"
+  - "pypy3.5"
+  - "pypy3"
 matrix:
   allow_failures:
     - python: "nightly"
-  include:
-    - { python: "3.7", dist: xenial, sudo: true }
 install:
-  - pip install --upgrade coveralls pytest "pytest-cov>=2.5.1" dataclasses
+  - pip install --upgrade coveralls pytest "pytest-cov>=2.5.1" dataclasses 
typing_extensions
   # 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.17.0/CHANGES new/injector-0.18.1/CHANGES
--- old/injector-0.17.0/CHANGES 2019-06-15 16:23:44.000000000 +0200
+++ new/injector-0.18.1/CHANGES 2019-12-10 02:25:28.000000000 +0100
@@ -1,6 +1,27 @@
 Injector Change Log
 ===================
 
+0.18.1
+------
+
+- Fixed UnsatisfiedRequirement instantiation (trying to get its string 
representation would fail)
+- Fixed injecting a subclass of a generic type on Python versions older than 
3.7.0
+- Fixed regression that caused BoundKey injection failure
+
+0.18.0
+------
+
+- Added new public :func:`get_bindings <injector.get_bindings>` function to 
see what parameters will be injected
+  into a function
+- Added new generic types using a draft implementation of `PEP 593 
<https://www.python.org/dev/peps/pep-0593/>`_:
+  :data:`Inject <injector.Inject>` and :data:`NoInject <injector.NoInject>`. 
Those serve as additional ways to
+  declare (non)injectable parameters while :func:`inject <injector.inject>` 
won't go away any time soon
+  :func:`noninjectable <injector.noninjectable>` may be removed once 
`NoInject` is cofirmed to work.
+
+Backwards incompatible:
+
+- Removed previously deprecated `Key`, `BindingKey`, `SequenceKey` and 
`MappingKey` pseudo-types
+
 0.17.0
 ------
 
@@ -43,7 +64,7 @@
 - Removed previously deprecated constructs: with_injector, 
Injector.install_into, Binder.bind_scope
 - Dependencies are no longer injected into Module.configure and raw module 
functions (previously
   deprecated)
-– Removed unofficial support for injecting into parent class constructors
+- Removed unofficial support for injecting into parent class constructors
 
 0.15.0
 ------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/README.md 
new/injector-0.18.1/README.md
--- old/injector-0.17.0/README.md       2019-06-15 16:23:44.000000000 +0200
+++ new/injector-0.18.1/README.md       2019-12-10 02:25:28.000000000 +0100
@@ -7,11 +7,50 @@
 Introduction
 ------------
 
-Dependency injection as a formal pattern is less useful in Python than in 
other languages, primarily due to its support for keyword arguments, the ease 
with which objects can be mocked, and its dynamic nature.
+While dependency injection is easy to do in Python due to its support for 
keyword arguments, the ease with which objects can be mocked and its dynamic 
natura, a framework for assisting in this process can remove a lot of 
boiler-plate from larger applications. That's where Injector can help. It 
automatically and transitively provides dependencies for you. As an added 
benefit, Injector encourages nicely compartmentalised code through the use of 
:ref:`modules <module>`.
 
-That said, a framework for assisting in this process can remove a lot of 
boiler-plate from larger applications. That's where Injector can help. It 
automatically and transitively provides keyword arguments with their values. As 
an added benefit, Injector encourages nicely compartmentalised code through the 
use of `Module` s.
+If you're not sure what dependency injection is or you'd like to learn more 
about it see:
 
-While being inspired by Guice, it does not slavishly replicate its API. 
Providing a Pythonic API trumps faithfulness.
+* [The Clean Code Talks - Don't Look For Things! (a talk by Miško Hevery)](
+  https://www.youtube.com/watch?v=RlfLCWKxHJ0)
+* [Inversion of Control Containers and the Dependency Injection pattern (an 
article by Martin Fowler)](
+  https://martinfowler.com/articles/injection.html)
+
+The core values of Injector are:
+
+* Simplicity - while being inspired by Guice, Injector does not slavishly 
replicate its API.
+  Providing a Pythonic API trumps faithfulness. Additionally some features are 
ommitted
+  because supporting them would be cumbersome and introduce a little bit too 
much "magic"
+  (member injection, method injection).
+
+  Connected to this, Injector tries to be as nonintrusive as possible. For 
example while you may
+  declare a class' constructor to expect some injectable parameters, the 
class' constructor
+  remains a standard constructor – you may instaniate the class just the same 
manually, if you want.
+
+* No global state – you can have as many 
[Injector](https://injector.readthedocs.io/en/latest/api.html#injector.Injector)
+  instances as you like, each with a different configuration and each with 
different objects in different
+  scopes. Code like this won't work for this very reason:
+
+  ```python
+    class MyClass:
+        @inject
+        def __init__(t: SomeType):
+            # ...
+
+    MyClass()
+  ```
+
+  This is simply because there's no global `Injector` to use. You need to be 
explicit and use
+  
[Injector.get](https://injector.readthedocs.io/en/latest/api.html#injector.Injector.get),
+  
[Injector.create_object](https://injector.readthedocs.io/en/latest/api.html#injector.Injector.create_object)
+  or inject `MyClass` into the place that needs it.
+
+* Cooperation with static type checking infrastructure – the API provides as 
much static type safety
+  as possible and only breaks it where there's no other option. For example the
+  
[Injector.get](https://injector.readthedocs.io/en/latest/api.html#injector.Injector.get)
 method
+  is typed such that `injector.get(SomeType)` is statically declared to return 
an instance of
+  `SomeType`, therefore making it possible for tools such as 
[mypy](https://github.com/python/mypy) to
+  type-check correctly the code using it.
 
 ### How to get Injector?
 
@@ -77,7 +116,7 @@
 
 
 ```python
->>> from injector import Module, Key, provider, Injector, inject, singleton
+>>> from injector import Module, provider, Injector, inject, singleton
 
 ```
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/conftest.py 
new/injector-0.18.1/conftest.py
--- old/injector-0.17.0/conftest.py     2019-06-15 16:23:44.000000000 +0200
+++ new/injector-0.18.1/conftest.py     1970-01-01 01:00:00.000000000 +0100
@@ -1,7 +0,0 @@
-import os.path
-
-test_sources = ['injector', 'injector_test.py', 'README.md']
-
-
-def pytest_ignore_collect(path, config):
-    return not os.path.basename(str(path)) in test_sources
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/docs/index.rst 
new/injector-0.18.1/docs/index.rst
--- old/injector-0.17.0/docs/index.rst  2019-06-15 16:23:44.000000000 +0200
+++ new/injector-0.18.1/docs/index.rst  2019-12-10 02:25:28.000000000 +0100
@@ -20,16 +20,61 @@
 
     pip install injector
 
+Injector works with CPython 3.5+ and PyPy 3 implementing Python 3.5+.
+
 Introduction
 ------------
 
-Dependency injection as a formal pattern is less useful in Python than in 
other languages, primarily due to its support for keyword arguments, the ease 
with which objects can be mocked, and its dynamic nature.
+While dependency injection is easy to do in Python due to its support for 
keyword arguments, the ease with which objects can be mocked and its dynamic 
natura, a framework for assisting in this process can remove a lot of 
boiler-plate from larger applications. That's where Injector can help. It 
automatically and transitively provides dependencies for you. As an added 
benefit, Injector encourages nicely compartmentalised code through the use of 
:ref:`modules <module>`.
+
+If you're not sure what dependency injection is or you'd like to learn more 
about it see:
+
+* `The Clean Code Talks - Don't Look For Things! (a talk by Miško Hevery)
+  <https://www.youtube.com/watch?v=RlfLCWKxHJ0>`_
+* `Inversion of Control Containers and the Dependency Injection pattern (an 
article by Martin Fowler)
+  <https://martinfowler.com/articles/injection.html>`_
+
+The core values of Injector are:
+
+* Simplicity - while being inspired by Guice, Injector does not slavishly 
replicate its API.
+  Providing a Pythonic API trumps faithfulness. Additionally some features are 
ommitted
+  because supporting them would be cumbersome and introduce a little bit too 
much "magic"
+  (member injection, method injection).
+
+  Connected to this, Injector tries to be as nonintrusive as possible. For 
example while you may
+  declare a class' constructor to expect some injectable parameters, the 
class' constructor
+  remains a standard constructor – you may instaniate the class just the same 
manually, if you want.
+
+* No global state – you can have as many :class:`Injector` instances as you 
like, each with
+  a different configuration and each with different objects in different 
scopes. Code like this
+  won't work for this very reason::
+
+    class MyClass:
+        @inject
+        def __init__(t: SomeType):
+            # ...
+
+    MyClass()
+
+  This is simply because there's no global :class:`Injector` to use. You need 
to be explicit and use
+  :meth:`Injector.get <injector.Injector.get>`,
+  :meth:`Injector.create_object <injector.Injector.create_object>` or inject 
`MyClass` into the place
+  that needs it.
+
+* Cooperation with static type checking infrastructure – the API provides as 
much static type safety
+  as possible and only breaks it where there's no other option. For example the
+  :meth:`Injector.get <injector.Injector.get>` method is typed such that 
`injector.get(SomeType)`
+  is statically declared to return an instance of `SomeType`, therefore making 
it possible for tools
+  such as `mypy <https://github.com/python/mypy>`_ to type-check correctly the 
code using it.
 
-That said, a framework for assisting in this process can remove a lot of 
boiler-plate from larger applications. That's where Injector can help. It 
automatically and transitively provides keyword arguments with their values. As 
an added benefit, Injector encourages nicely compartmentalised code through the 
use of :ref:`modules <module>`.
+Quick start
+-----------
 
-While being inspired by Guice, it does not slavishly replicate its API. 
Providing a Pythonic API trumps faithfulness.
+See `the project's README 
<https://github.com/alecthomas/injector/blob/master/README.md>`_ for an
+example of Injector use.
 
-Contents:
+Contents
+--------
 
 .. toctree::
    :maxdepth: 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/injector/__init__.py 
new/injector-0.18.1/injector/__init__.py
--- old/injector-0.17.0/injector/__init__.py    2019-06-15 16:23:44.000000000 
+0200
+++ new/injector-0.18.1/injector/__init__.py    2019-12-10 02:25:28.000000000 
+0100
@@ -21,29 +21,36 @@
 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,
-    overload,
-    Tuple,
-    Type,
-    TypeVar,
-    Union,
-)
+from typing import Any, Callable, cast, Dict, Generic, List, Optional, 
overload, Tuple, Type, TypeVar, Union
+
+HAVE_ANNOTATED = sys.version_info >= (3, 7, 0)
+
+if HAVE_ANNOTATED:
+    # Ignoring errors here as typing_extensions stub doesn't know about those 
things yet
+    from typing_extensions import _AnnotatedAlias, Annotated, get_type_hints  
# type: ignore
+else:
+
+    class Annotated:  # type: ignore
+        pass
+
+    from typing import get_type_hints as _get_type_hints
+
+    def get_type_hints(
+        obj: Callable[..., Any],
+        globalns: Optional[Dict[str, Any]] = None,
+        localns: Optional[Dict[str, Any]] = None,
+        include_extras: bool = False,
+    ) -> Dict[str, Any]:
+        return _get_type_hints(obj, globalns, localns)
+
 
 TYPING353 = hasattr(Union[str, int], '__origin__')
 
 
 __author__ = 'Alec Thomas <a...@swapoff.org>'
-__version__ = '0.17.0'
+__version__ = '0.18.1'
 __version_tag__ = ''
 
 log = logging.getLogger('injector')
@@ -80,6 +87,91 @@
 lock = threading.RLock()
 
 
+_inject_marker = object()
+_noinject_marker = object()
+
+if HAVE_ANNOTATED:
+    InjectT = TypeVar('InjectT')
+    Inject = Annotated[InjectT, _inject_marker]
+    """An experimental way to declare injectable dependencies utilizing a `PEP 
593`_ implementation
+    in `typing_extensions`.
+
+    Those two declarations are equivalent::
+
+        @inject
+        def fun(t: SomeType) -> None:
+            pass
+
+        def fun(t: Inject[SomeType]) -> None:
+            pass
+
+    The advantage over using :func:`inject` is that if you have some 
noninjectable parameters
+    it may be easier to spot what are they. Those two are equivalent::
+
+        @inject
+        @noninjectable('s')
+        def fun(t: SomeType, s: SomeOtherType) -> None:
+            pass
+
+        def fun(t: Inject[SomeType], s: SomeOtherType) -> None:
+            pass
+
+    .. seealso::
+
+        Function :func:`get_bindings`
+            A way to inspect how various injection declarations interact with 
each other.
+
+    .. versionadded:: 0.18.0
+    .. note:: Requires Python 3.7+.
+    .. note::
+
+        If you're using mypy you need the version 0.750 or newer to fully 
type-check code using this
+        construct.
+
+    .. _PEP 593: https://www.python.org/dev/peps/pep-0593/
+    .. _typing_extensions: https://pypi.org/project/typing-extensions/
+    """
+
+    NoInject = Annotated[InjectT, _noinject_marker]
+    """An experimental way to declare noninjectable dependencies utilizing a 
`PEP 593`_ implementation
+    in `typing_extensions`.
+
+    Since :func:`inject` declares all function's parameters to be injectable 
there needs to be a way
+    to opt out of it. This has been provided by :func:`noninjectable` but 
`noninjectable` suffers from
+    two issues:
+
+    * You need to repeat the parameter name
+    * The declaration may be relatively distance in space from the actual 
parameter declaration, thus
+      hindering readability
+
+    `NoInject` solves both of those concerns, for example (those two 
declarations are equivalent)::
+
+        @inject
+        @noninjectable('b')
+        def fun(a: TypeA, b: TypeB) -> None:
+            pass
+
+        @inject
+        def fun(a: TypeA, b: NoInject[TypeB]) -> None:
+            pass
+
+    .. seealso::
+
+        Function :func:`get_bindings`
+            A way to inspect how various injection declarations interact with 
each other.
+
+    .. versionadded:: 0.18.0
+    .. note:: Requires Python 3.7+.
+    .. note::
+
+        If you're using mypy you need the version 0.750 or newer to fully 
type-check code using this
+        construct.
+
+    .. _PEP 593: https://www.python.org/dev/peps/pep-0593/
+    .. _typing_extensions: https://pypi.org/project/typing-extensions/
+    """
+
+
 def reraise(original: Exception, exception: Exception, maximum_frames: int = 
1) -> None:
     prev_cls, prev, tb = sys.exc_info()
     frames = inspect.getinnerframes(cast(types.TracebackType, tb))
@@ -170,16 +262,19 @@
 
     ::
 
-        >>> key = Key('key')
+        >>> class MyClass:
+        ...     def __init__(self, value: int) -> None:
+        ...         self.value = value
+        ...
         >>> def factory():
         ...     print('providing')
-        ...     return []
+        ...     return MyClass(42)
         ...
         >>> def configure(binder):
-        ...     binder.bind(key, to=CallableProvider(factory))
+        ...     binder.bind(MyClass, to=CallableProvider(factory))
         ...
         >>> injector = Injector(configure)
-        >>> injector.get(key) is injector.get(key)
+        >>> injector.get(MyClass) is injector.get(MyClass)
         providing
         providing
         False
@@ -200,15 +295,17 @@
 
     ::
 
-        >>> my_list = Key('my_list')
+        >>> class MyType:
+        ...     def __init__(self):
+        ...         self.contents = []
         >>> def configure(binder):
-        ...     binder.bind(my_list, to=InstanceProvider([]))
+        ...     binder.bind(MyType, to=InstanceProvider(MyType()))
         ...
         >>> injector = Injector(configure)
-        >>> injector.get(my_list) is injector.get(my_list)
+        >>> injector.get(MyType) is injector.get(MyType)
         True
-        >>> injector.get(my_list).append('x')
-        >>> injector.get(my_list)
+        >>> injector.get(MyType).contents.append('x')
+        >>> injector.get(MyType).contents
         ['x']
     """
 
@@ -257,37 +354,6 @@
         return map
 
 
-@private
-class BindingKey(tuple):
-    """A key mapping to a Binding."""
-
-    @classmethod
-    def create(cls, what: Any) -> 'BindingKey':
-        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,))
-
-    @property
-    def interface(self):
-        return self[0]
-
-
 _BindingBase = namedtuple('_BindingBase', 'interface provider scope')
 
 
@@ -307,7 +373,7 @@
     """
 
     @private
-    def __init__(self, injector, auto_bind=True, parent=None):
+    def __init__(self, injector: 'Injector', auto_bind: bool = True, parent: 
'Binder' = None) -> None:
         """Create a new Binder.
 
         :param injector: Injector we are binding for.
@@ -316,10 +382,15 @@
         """
         self.injector = injector
         self._auto_bind = auto_bind
-        self._bindings = {}
+        self._bindings = {}  # type: Dict[type, Binding]
         self.parent = parent
 
-    def bind(self, interface, to=None, scope=None):
+    def bind(
+        self,
+        interface: Type[T],
+        to: Union[None, T, Callable[..., T], Provider[T]] = None,
+        scope: Union[None, Type['Scope'], 'ScopeDecorator'] = None,
+    ) -> None:
         """Bind an interface to an implementation.
 
         `typing.List` and `typing.Dict` instances are reserved for 
multibindings and trying to bind them
@@ -327,28 +398,16 @@
 
             binder.bind(List[str], to=['hello', 'there'])  # Error
 
-        :param interface: Interface or :func:`Key` to bind.
+        :param interface: Type to bind.
         :param to: Instance or class to bind to, or an explicit
              :class:`Provider` subclass.
         :param scope: Optional :class:`Scope` in which to bind.
         """
-        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
+        self._bindings[interface] = self.create_binding(interface, to, scope)
 
     @overload
     def multibind(
@@ -386,13 +445,12 @@
             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 interface: 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 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 interface not in self._bindings:
             if (
                 isinstance(interface, dict)
                 or isinstance(interface, type)
@@ -403,14 +461,14 @@
             else:
                 provider = MultiBindProvider()
             binding = self.create_binding(interface, provider, scope)
-            self._bindings[key] = binding
+            self._bindings[interface] = binding
         else:
-            binding = self._bindings[key]
+            binding = self._bindings[interface]
             provider = binding.provider
             assert isinstance(provider, ListOfProviders)
-        provider.append(self.provider_for(key.interface, to))
+        provider.append(self.provider_for(interface, to))
 
-    def install(self, module):
+    def install(self, module: Union[Callable[['Binder'], None], 'Module', 
Type['Module']]) -> None:
         """Install a module into this binder.
 
         In this context the module is one of the following:
@@ -441,8 +499,8 @@
 
             binder.install(MyModule)
         """
-        if type(module) is type and issubclass(module, Module):
-            instance = module()
+        if type(module) is type and issubclass(cast(type, module), Module):
+            instance = cast(type, module)()
         else:
             instance = module
         instance(self)
@@ -482,10 +540,14 @@
             return ClassProvider(to)
         elif isinstance(interface, BoundKey):
 
-            def proxy(**kwargs):
+            def proxy(injector: Injector):
+                binder = injector.binder
+                kwarg_providers = {
+                    name: binder.provider_for(None, provider) for (name, 
provider) in interface.kwargs.items()
+                }
+                kwargs = {name: provider.get(injector) for (name, provider) in 
kwarg_providers.items()}
                 return interface.interface(**kwargs)
 
-            proxy.__annotations__ = interface.kwargs.copy()
             return CallableProvider(inject(proxy))
         elif _is_specialization(interface, AssistedBuilder):
             (target,) = interface.__args__
@@ -517,23 +579,23 @@
 
         raise KeyError
 
-    def get_binding(self, key):
-        is_scope = isinstance(key.interface, type) and 
issubclass(key.interface, Scope)
+    def get_binding(self, interface):
+        is_scope = isinstance(interface, type) and issubclass(interface, Scope)
         try:
-            return self._get_binding(key, only_this_binder=is_scope)
+            return self._get_binding(interface, only_this_binder=is_scope)
         except (KeyError, UnsatisfiedRequirement):
             if is_scope:
-                scope = key.interface
+                scope = interface
                 self.bind(scope, to=scope(self.injector))
-                return self._get_binding(key)
+                return self._get_binding(interface)
             # The special interface is added here so that requesting a special
             # interface with auto_bind disabled works
-            if self._auto_bind or self._is_special_interface(key.interface):
-                binding = self.create_binding(key.interface)
-                self._bindings[key] = binding
+            if self._auto_bind or self._is_special_interface(interface):
+                binding = self.create_binding(interface)
+                self._bindings[interface] = binding
                 return binding, self
 
-        raise UnsatisfiedRequirement(key)
+        raise UnsatisfiedRequirement(None, interface)
 
     def _is_special_interface(self, interface):
         # "Special" interfaces are ones that you cannot bind yourself but
@@ -549,6 +611,13 @@
         # issubclass(SomeGeneric[X], SomeGeneric) so we need some other way to
         # determine whether a particular object is a generic class with type 
parameters
         # provided. Fortunately there seems to be __origin__ attribute that's 
useful here.
+
+        # We need to special-case Annotated as its __origin__ behaves 
differently than
+        # other typing generic classes. See 
https://github.com/python/typing/pull/635
+        # for some details.
+        if HAVE_ANNOTATED and generic_class is Annotated and isinstance(cls, 
_AnnotatedAlias):
+            return True
+
         if not hasattr(cls, '__origin__'):
             return False
         origin = cls.__origin__
@@ -631,9 +700,6 @@
 class NoScope(Scope):
     """An unscoped provider."""
 
-    def __init__(self, injector=None):
-        super(NoScope, self).__init__(injector)
-
     def get(self, unused_key, provider):
         return provider
 
@@ -786,20 +852,18 @@
         :param scope: Class of the Scope in which to resolve.
         :returns: An implementation of interface.
         """
-        key = BindingKey.create(interface)
-        binding, binder = self.binder.get_binding(key)
+        binding, binder = self.binder.get_binding(interface)
         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(scope_key)
+        scope_binding, _ = binder.get_binding(scope)
         scope_instance = scope_binding.provider.get(self)
 
         log.debug(
             '%sInjector.get(%r, scope=%r) using %r', self._log_prefix, 
interface, scope, binding.provider
         )
-        result = scope_instance.get(key, binding.provider).get(self)
+        result = scope_instance.get(interface, binding.provider).get(self)
         log.debug('%s -> %r', self._log_prefix, result)
         return result
 
@@ -823,19 +887,7 @@
             init = cls.__init__
             self.call_with_injection(init, self_=instance, 
kwargs=additional_kwargs)
         except TypeError as e:
-            # The reason why getattr() fallback is used here is that
-            # __init__.__func__ apparently doesn't exist for Key-type objects
-            reraise(
-                e,
-                CallError(
-                    instance,
-                    getattr(instance.__init__, '__func__', instance.__init__),
-                    (),
-                    additional_kwargs,
-                    e,
-                    self._stack,
-                ),
-            )
+            reraise(e, CallError(instance, instance.__init__.__func__, (), 
additional_kwargs, e, self._stack))
         return instance
 
     def call_with_injection(self, callable, self_=None, args=(), kwargs={}):
@@ -851,16 +903,7 @@
         :return: Value returned by callable.
         """
 
-        def _get_callable_bindings(callable):
-            if not hasattr(callable, '__bindings__'):
-                return {}
-
-            if callable.__bindings__ == 'deferred':
-                read_and_store_bindings(callable, 
_infer_injected_bindings(callable))
-            return callable.__bindings__
-
-        bindings = _get_callable_bindings(callable)
-        noninjectables = getattr(callable, '__noninjectables__', set())
+        bindings = get_bindings(callable)
         signature = inspect.signature(callable)
         full_args = args
         if self_ is not None:
@@ -868,9 +911,7 @@
         bound_arguments = signature.bind_partial(*full_args)
 
         needed = dict(
-            (k, v)
-            for (k, v) in bindings.items()
-            if k not in kwargs and k not in noninjectables and k not in 
bound_arguments.arguments
+            (k, v) for (k, v) in bindings.items() if k not in kwargs and k not 
in bound_arguments.arguments
         )
 
         dependencies = self.args_to_inject(
@@ -915,9 +956,9 @@
 
         self._stack += (key,)
         try:
-            for arg, key in bindings.items():
+            for arg, interface in bindings.items():
                 try:
-                    instance = self.get(key.interface)
+                    instance = self.get(interface)
                 except UnsatisfiedRequirement as e:
                     if not e.args[0]:
                         e = UnsatisfiedRequirement(owner_key, e.args[1])
@@ -929,14 +970,102 @@
         return dependencies
 
 
+def get_bindings(callable: Callable) -> Dict[str, type]:
+    """Get bindings of injectable parameters from a callable.
+
+    If the callable is not decorated with :func:`inject` and does not have any 
of its
+    parameters declared as injectable using :data:`Inject` an empty dictionary 
will
+    be returned.  Otherwise the returned dictionary will contain a mapping
+    between parameter names and their types with the exception of parameters
+    excluded from dependency injection (either with :func:`noninjectable`, 
:data:`NoInject`
+    or only explicit injection with :data:`Inject` being used). For example::
+
+        >>> def function1(a: int) -> None:
+        ...     pass
+        ...
+        >>> get_bindings(function1)
+        {}
+
+        >>> @inject
+        ... def function2(a: int) -> None:
+        ...     pass
+        ...
+        >>> get_bindings(function2)
+        {'a': <class 'int'>}
+
+        >>> @inject
+        ... @noninjectable('b')
+        ... def function3(a: int, b: str) -> None:
+        ...     pass
+        ...
+        >>> get_bindings(function3)
+        {'a': <class 'int'>}
+
+        >>> import sys, pytest
+        >>> if sys.version_info < (3, 7, 0):
+        ...     pytest.skip('Python 3.7.0 required for sufficient Annotated 
support')
+
+        >>> # The simple case of no @inject but injection requested with 
Inject[...]
+        >>> def function4(a: Inject[int], b: str) -> None:
+        ...     pass
+        ...
+        >>> get_bindings(function4)
+        {'a': <class 'int'>}
+
+        >>> # Using @inject with Inject is redundant but it should not break 
anything
+        >>> @inject
+        ... def function5(a: Inject[int], b: str) -> None:
+        ...     pass
+        ...
+        >>> get_bindings(function5)
+        {'a': <class 'int'>, 'b': <class 'str'>}
+
+        >>> # We need to be able to exclude a parameter from injection with 
NoInject
+        >>> @inject
+        ... def function6(a: int, b: NoInject[str]) -> None:
+        ...     pass
+        ...
+        >>> get_bindings(function6)
+        {'a': <class 'int'>}
+
+        >>> # The presence of NoInject should not trigger anything on its own
+        >>> def function7(a: int, b: NoInject[str]) -> None:
+        ...     pass
+        ...
+        >>> get_bindings(function7)
+        {}
+
+    This function is used internally so by calling it you can learn what 
exactly
+    Injector is going to try to provide to a callable.
+    """
+    look_for_explicit_bindings = False
+    if not hasattr(callable, '__bindings__'):
+        type_hints = get_type_hints(callable, include_extras=True)
+        has_injectable_parameters = any(
+            _is_specialization(v, Annotated) and _inject_marker in 
v.__metadata__ for v in type_hints.values()
+        )
+
+        if not has_injectable_parameters:
+            return {}
+        else:
+            look_for_explicit_bindings = True
+
+    if look_for_explicit_bindings or cast(Any, callable).__bindings__ == 
'deferred':
+        read_and_store_bindings(
+            callable, _infer_injected_bindings(callable, 
only_explicit_bindings=look_for_explicit_bindings)
+        )
+    noninjectables = getattr(callable, '__noninjectables__', set())
+    return {k: v for k, v in cast(Any, callable).__bindings__.items() if k not 
in noninjectables}
+
+
 class _BindingNotYetAvailable(Exception):
     pass
 
 
-def _infer_injected_bindings(callable):
+def _infer_injected_bindings(callable, only_explicit_bindings: bool):
     spec = inspect.getfullargspec(callable)
     try:
-        bindings = get_type_hints(callable)
+        bindings = get_type_hints(callable, include_extras=True)
     except NameError as e:
         raise _BindingNotYetAvailable(e)
 
@@ -952,10 +1081,22 @@
 
     # variadic arguments aren't supported at the moment (this may change
     # in the future if someone has a good idea how to utilize them)
-    bindings.pop(spec.varargs, None)
-    bindings.pop(spec.varkw, None)
+    if spec.varargs:
+        bindings.pop(spec.varargs, None)
+    if spec.varkw:
+        bindings.pop(spec.varkw, None)
 
     for k, v in list(bindings.items()):
+        if _is_specialization(v, Annotated):
+            v, metadata = v.__origin__, v.__metadata__
+            bindings[k] = v
+        else:
+            metadata = tuple()
+
+        if only_explicit_bindings and _inject_marker not in metadata or 
_noinject_marker in metadata:
+            del bindings[k]
+            break
+
         if _is_specialization(v, Union):
             # We don't treat Optional parameters in any special way at the 
moment.
             if TYPING353:
@@ -963,7 +1104,9 @@
             else:
                 union_members = v.__union_params__
             new_members = tuple(set(union_members) - {type(None)})
-            new_union = Union[new_members]
+            # mypy stared complaining about this line for some reason:
+            #     error: Variable "new_members" is not valid as a type
+            new_union = Union[new_members]  # type: ignore
             # mypy complains about this construct:
             #     error: The type alias is invalid in runtime context
             # See: https://github.com/python/mypy/issues/5354
@@ -1038,40 +1181,36 @@
 
     eg.
 
-    >>> Sizes = Key('sizes')
-    >>> Names = Key('names')
-    >>>
     >>> class A:
     ...     @inject
-    ...     def __init__(self, number: int, name: str, sizes: Sizes):
-    ...         print([number, name, sizes])
+    ...     def __init__(self, number: int, name: str):
+    ...         print([number, name])
     ...
     >>> def configure(binder):
     ...     binder.bind(A)
     ...     binder.bind(int, to=123)
     ...     binder.bind(str, to='Bob')
-    ...     binder.bind(Sizes, to=[1, 2, 3])
 
     Use the Injector to get a new instance of A:
 
     >>> a = Injector(configure).get(A)
-    [123, 'Bob', [1, 2, 3]]
+    [123, 'Bob']
 
-    As a convenience one can decorate a class itself:
+    As a convenience one can decorate a class itself::
 
-    >>> @inject
-    ... class B:
-    ...     def __init__(self, dependency: Dependency):
-    ...         self.dependency = dependency
+        @inject
+        class B:
+            def __init__(self, dependency: Dependency):
+                self.dependency = dependency
 
     This is equivalent to decorating its constructor. In particular this 
provides integration with
     `dataclasses <https://docs.python.org/3/library/dataclasses.html>`_ (the 
order of decorator
-    application is important here):
+    application is important here)::
 
-    >>> @inject
-    ... @dataclass
-    ... class C:
-    ...     dependency: Dependency
+        @inject
+        @dataclass
+        class C:
+            dependency: Dependency
 
     .. note::
 
@@ -1082,6 +1221,14 @@
         Third party libraries may, however, provide support for injecting 
dependencies
         into non-constructor methods or free functions in one form or another.
 
+    .. seealso::
+
+        Generic type :data:`Inject`
+            A more explicit way to declare parameters as injectable.
+
+        Function :func:`get_bindings`
+            A way to inspect how various injection declarations interact with 
each other.
+
     .. versionchanged:: 0.16.2
 
         (Re)added support for decorating classes with @inject.
@@ -1091,7 +1238,7 @@
     else:
         function = constructor_or_class
         try:
-            bindings = _infer_injected_bindings(function)
+            bindings = _infer_injected_bindings(function, 
only_explicit_bindings=False)
             read_and_store_bindings(function, bindings)
         except _BindingNotYetAvailable:
             function.__bindings__ = 'deferred'
@@ -1120,6 +1267,15 @@
     each other and the order in which a function is decorated with
     :func:`inject` and :func:`noninjectable`
     doesn't matter.
+
+    .. seealso::
+
+        Generic type :data:`NoInject`
+            A nicer way to declare parameters as noninjectable.
+
+        Function :func:`get_bindings`
+            A way to inspect how various injection declarations interact with 
each other.
+
     """
 
     def decorator(function):
@@ -1138,8 +1294,6 @@
 
 @private
 def read_and_store_bindings(f, bindings):
-    for key, value in bindings.items():
-        bindings[key] = BindingKey.create(value)
     function_bindings = getattr(f, '__bindings__', None) or {}
     if function_bindings == 'deferred':
         function_bindings = {}
@@ -1150,75 +1304,6 @@
     f.__bindings__ = merged_bindings
 
 
-@private
-class BaseKey:
-    """Base type for binding keys."""
-
-    def __init__(self) -> None:
-        raise Exception(
-            'Instantiation of %s prohibited - it is derived from BaseKey '
-            'so most likely you should bind it to something.' % 
(self.__class__,)
-        )
-
-
-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,), {}))
-
-
-@private
-class BaseMappingKey(dict):
-    """Base type for mapping binding keys."""
-
-    def __init__(self) -> None:
-        raise Exception(
-            'Instantiation of %s prohibited - it is derived from 
BaseMappingKey '
-            'so most likely you should bind it to something.' % 
(self.__class__,)
-        )
-
-
-def MappingKey(name: str) -> BaseMappingKey:
-    """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,), {}))
-
-
-@private
-class BaseSequenceKey(list):
-    """Base type for mapping sequence keys."""
-
-    def __init__(self) -> None:
-        raise Exception(
-            'Instantiation of %s prohibited - it is derived from 
BaseSequenceKey '
-            'so most likely you should bind it to something.' % 
(self.__class__,)
-        )
-
-
-def SequenceKey(name: str) -> BaseSequenceKey:
-    """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,), {}))
-
-
 class BoundKey(tuple):
     """A BoundKey provides a key to a type with pre-injected arguments.
 
@@ -1252,9 +1337,8 @@
         self._target = target
 
     def build(self, **kwargs: Any) -> T:
-        key = BindingKey.create(self._target)
         binder = self._injector.binder
-        binding, _ = binder.get_binding(key)
+        binding, _ = binder.get_binding(self._target)
         provider = binding.provider
         if not isinstance(provider, ClassProvider):
             raise Error(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/injector_test.py 
new/injector-0.18.1/injector_test.py
--- old/injector-0.17.0/injector_test.py        2019-06-15 16:23:44.000000000 
+0200
+++ new/injector-0.18.1/injector_test.py        2019-12-10 02:25:28.000000000 
+0100
@@ -29,6 +29,7 @@
     Scope,
     InstanceProvider,
     ClassProvider,
+    get_bindings,
     inject,
     multiprovider,
     noninjectable,
@@ -37,20 +38,20 @@
     UnsatisfiedRequirement,
     CircularDependency,
     Module,
-    Key,
     SingletonScope,
     ScopeDecorator,
     AssistedBuilder,
-    BindingKey,
-    SequenceKey,
-    MappingKey,
     provider,
     ProviderOf,
     ClassAssistedBuilder,
     Error,
     UnknownArgument,
+    HAVE_ANNOTATED,
 )
 
+if HAVE_ANNOTATED:
+    from injector import Inject, NoInject
+
 
 def prepare_basic_injection():
     class B:
@@ -97,20 +98,20 @@
 
 
 def test_child_injector_rebinds_arguments_for_parent_scope():
-    I = Key("interface")
-    Cls = Key("test_class")
+    class Cls:
+        val = ""
 
-    class A:
+    class A(Cls):
         @inject
-        def __init__(self, val: I):
+        def __init__(self, val: str):
             self.val = val
 
     def configure_parent(binder):
         binder.bind(Cls, to=A)
-        binder.bind(I, to="Parent")
+        binder.bind(str, to="Parent")
 
     def configure_child(binder):
-        binder.bind(I, to="Child")
+        binder.bind(str, to="Child")
 
     parent = Injector(configure_parent)
     assert parent.get(Cls).val == "Parent"
@@ -128,16 +129,6 @@
     assert parent.get(A) is child.get(A)
 
 
-def test_key_cannot_be_instantiated():
-    Interface = Key('Interface')
-
-    with pytest.raises(Exception):
-        Interface()
-
-    with pytest.raises(Exception):
-        Injector().get(Interface)
-
-
 def test_get_default_injected_instances():
     A, B = prepare_basic_injection()
 
@@ -472,40 +463,6 @@
     assert injector.get(str) == name
 
 
-def test_bind_using_key():
-    Name = Key('name')
-    Age = Key('age')
-
-    class MyModule(Module):
-        @provider
-        def provider_name(self) -> Name:
-            return 'Bob'
-
-        def configure(self, binder):
-            binder.bind(Age, to=25)
-
-    injector = Injector(MyModule())
-    assert injector.get(Age) == 25
-    assert injector.get(Name) == 'Bob'
-
-
-def test_inject_using_key():
-    Name = Key('name')
-    Description = Key('description')
-
-    class MyModule(Module):
-        @provider
-        def provide_name(self) -> Name:
-            return 'Bob'
-
-        @provider
-        @inject
-        def provide_description(self, name: Name) -> Description:
-            return '%s is cool!' % name
-
-    assert Injector(MyModule()).get(Description) == 'Bob is cool!'
-
-
 def test_inject_and_provide_coexist_happily():
     class MyModule(Module):
         @provider
@@ -525,18 +482,6 @@
     assert Injector(MyModule()).get(str) == 'Bob is 25 and weighs 50.0kg'
 
 
-def test_multibind_old():
-    Names = Key('names')
-
-    def configure_one(binder):
-        binder.multibind(Names, to=['Bob'])
-
-    def configure_two(binder):
-        binder.multibind(Names, to=['Tom'])
-
-    assert Injector([configure_one, configure_two]).get(Names) == ['Bob', 
'Tom']
-
-
 def test_multibind():
     Names = NewType('Names', List[str])
     Passwords = NewType('Ages', Dict[str, str])
@@ -634,21 +579,6 @@
         binder.bind(Passwords, to={})
 
 
-def test_provider_sequence_decorator():
-    Names = SequenceKey('names')
-
-    class MyModule(Module):
-        @provider
-        def bob(self) -> Names:
-            return ['Bob']
-
-        @provider
-        def tom(self) -> Names:
-            return ['Tom']
-
-    assert Injector(MyModule()).get(Names) == ['Bob', 'Tom']
-
-
 def test_auto_bind():
     class A:
         pass
@@ -723,36 +653,6 @@
         injector.get(Handler)
 
 
-def test_bind_interface_of_list_of_types():
-    def configure(binder):
-        binder.multibind([int], to=[1, 2, 3])
-        binder.multibind([int], to=[4, 5, 6])
-
-    injector = Injector(configure)
-    assert injector.get([int]) == [1, 2, 3, 4, 5, 6]
-
-
-def test_provider_mapping():
-
-    StrInt = MappingKey('StrInt')
-
-    def configure(binder):
-        binder.multibind(StrInt, to={'one': 1})
-        binder.multibind(StrInt, to={'two': 2})
-
-    class MyModule(Module):
-        @provider
-        def provide_numbers(self) -> StrInt:
-            return {'three': 3}
-
-        @provider
-        def provide_more_numbers(self) -> StrInt:
-            return {'four': 4}
-
-    injector = Injector([configure, MyModule()])
-    assert injector.get(StrInt) == {'one': 1, 'two': 2, 'three': 3, 'four': 4}
-
-
 def test_binder_install():
     class ModuleA(Module):
         def configure(self, binder):
@@ -874,7 +774,8 @@
 
 
 def test_assisted_builder_uses_bindings():
-    Interface = Key('Interface')
+    class Interface:
+        b = 0
 
     def configure(binder):
         binder.bind(Interface, to=NeedsAssistance)
@@ -910,12 +811,6 @@
     assert (b1._injector, b2._injector) == (i1, i2)
 
 
-def test_assisted_builder_injection_uses_the_same_binding_key_every_time():
-    # if we have different BindingKey for every AssistedBuilder(...) we will 
get memory leak
-    gen_key = lambda: BindingKey.create(AssistedBuilder[NeedsAssistance])
-    assert gen_key() == gen_key()
-
-
 class TestThreadSafety:
     def setup(self):
         self.event = threading.Event()
@@ -990,8 +885,8 @@
 
 
 def test_callable_provider_injection():
-    Name = Key("Name")
-    Message = Key("Message")
+    Name = NewType("Name", str)
+    Message = NewType("Message", str)
 
     @inject
     def create_message(name: Name):
@@ -1420,17 +1315,17 @@
 
 # The test taken from Alec Thomas' pull request: 
https://github.com/alecthomas/injector/pull/73
 def test_child_scope():
-    TestKey = Key('TestKey')
-    TestKey2 = Key('TestKey2')
+    TestKey = NewType('TestKey', str)
+    TestKey2 = NewType('TestKey2', str)
 
     def parent_module(binder):
-        binder.bind(TestKey, to=object, scope=singleton)
+        binder.bind(TestKey, to='in parent', scope=singleton)
 
     def first_child_module(binder):
-        binder.bind(TestKey2, to=object, scope=singleton)
+        binder.bind(TestKey2, to='in first child', scope=singleton)
 
     def second_child_module(binder):
-        binder.bind(TestKey2, to='marker', scope=singleton)
+        binder.bind(TestKey2, to='in second child', scope=singleton)
 
     injector = Injector(modules=[parent_module])
     first_child_injector = 
injector.create_child_injector(modules=[first_child_module])
@@ -1527,3 +1422,50 @@
 
     injector = Injector([configure])
     assert injector.get(Data).name == 'data'
+
+
+def test_get_bindings():
+    def function1(a: int) -> None:
+        pass
+
+    assert get_bindings(function1) == {}
+
+    @inject
+    def function2(a: int) -> None:
+        pass
+
+    assert get_bindings(function2) == {'a': int}
+
+    @inject
+    @noninjectable('b')
+    def function3(a: int, b: str) -> None:
+        pass
+
+    assert get_bindings(function3) == {'a': int}
+
+    if HAVE_ANNOTATED:
+        # The simple case of no @inject but injection requested with 
Inject[...]
+        def function4(a: Inject[int], b: str) -> None:
+            pass
+
+        assert get_bindings(function4) == {'a': int}
+
+        # Using @inject with Inject is redundant but it should not break 
anything
+        @inject
+        def function5(a: Inject[int], b: str) -> None:
+            pass
+
+        assert get_bindings(function5) == {'a': int, 'b': str}
+
+        # We need to be able to exclude a parameter from injection with 
NoInject
+        @inject
+        def function6(a: int, b: NoInject[str]) -> None:
+            pass
+
+        assert get_bindings(function6) == {'a': int}
+
+        # The presence of NoInject should not trigger anything on its own
+        def function7(a: int, b: NoInject[str]) -> None:
+            pass
+
+        assert get_bindings(function7) == {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/pytest.ini 
new/injector-0.18.1/pytest.ini
--- old/injector-0.17.0/pytest.ini      2019-06-15 16:23:44.000000000 +0200
+++ new/injector-0.18.1/pytest.ini      2019-12-10 02:25:28.000000000 +0100
@@ -1,4 +1,3 @@
 [pytest]
-python_files = injector_test.py injector_test_py3.py
 addopts = -v --tb=native --doctest-glob=*.md --doctest-modules --cov-report 
term --cov-report html --cov-report xml --cov=injector --cov-branch
 norecursedirs = __pycache__ *venv* .git build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/setup.cfg 
new/injector-0.18.1/setup.cfg
--- old/injector-0.17.0/setup.cfg       2019-06-15 16:23:44.000000000 +0200
+++ new/injector-0.18.1/setup.cfg       2019-12-10 02:25:28.000000000 +0100
@@ -1,5 +1,2 @@
-[pytest]
-addopts = -rsxX -q --doctest-modules --doctest-glob=README.md injector 
injector_test.py README.md
-
 [wheel]
 universal = True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.17.0/setup.py new/injector-0.18.1/setup.py
--- old/injector-0.17.0/setup.py        2019-06-15 16:23:44.000000000 +0200
+++ new/injector-0.18.1/setup.py        2019-12-10 02:25:28.000000000 +0100
@@ -69,4 +69,5 @@
         'IoC',
         'Inversion of Control container',
     ],
+    install_requires=['typing_extensions>=3.7.4'],
 )


Reply via email to