python-injector / python-injector/injector

Issue with injecting Generic classes - broke in python 3.7

Open
#175 10 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1.5k
Forks
94
PR merge metrics
No merged PRs in 30d

Description

Hi there, currently upgrading a project using injector to python 3.8. We use MyPy generics in our project and I discovered that I can no longer inject my generic class.

On further investigation, this seems to be still present in master, works in python 3.6.8, then is broken in anything 3.7 and above.

The following unit test reproduces the issue:

GenericType = TypeVar("GenericType")


def test_inject_generic_class() -> None:

    class GenericClass(Generic[GenericType]):
        pass

    class InjectsGeneric:
        @inject
        def __init__(self, injected_generic: GenericClass[str]):
            self.injected_generic = injected_generic

    def bindings(binder: Binder) -> None:
        binder.bind(GenericClass)

    injector = Injector(bindings)
    instance = injector.get(InjectsGeneric)

    assert isinstance(instance, InjectsGeneric)
    assert isinstance(instance.injected_generic, GenericClass)

Output on the failing python versions is:

______________________ test_inject_simple_generic_class _______________________
Traceback (most recent call last):
  File "D:\git\injector\injector\__init__.py", line 658, in get_binding
    return self._get_binding(interface, only_this_binder=is_scope)
  File "D:\git\injector\injector\__init__.py", line 653, in _get_binding
    raise KeyError
KeyError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\git\injector\injector_test.py", line 1494, in test_inject_simple_generic_class
    instance = injector.get(InjectsGeneric)
  File "D:\git\injector\injector\__init__.py", line 963, in get
    result = scope_instance.get(interface, binding.provider).get(self)
  File "D:\git\injector\injector\__init__.py", line 291, in get
    return injector.create_object(self._cls)
  File "D:\git\injector\injector\__init__.py", line 990, in create_object
    self.call_with_injection(cls.__init__, self_=instance, kwargs=additional_kwargs)
  File "D:\git\injector\injector\__init__.py", line 1021, in call_with_injection
    dependencies = self.args_to_inject(
  File "D:\git\injector\injector\__init__.py", line 111, in wrapper
    return function(*args, **kwargs)
  File "D:\git\injector\injector\__init__.py", line 1069, in args_to_inject
    instance = self.get(interface)  # type: Any
  File "D:\git\injector\injector\__init__.py", line 952, in get
    binding, binder = self.binder.get_binding(interface)
  File "D:\git\injector\injector\__init__.py", line 667, in get_binding
    binding = self.create_binding(interface)
  File "D:\git\injector\injector\__init__.py", line 582, in create_binding
    provider = self.provider_for(interface, to)
  File "D:\git\injector\injector\__init__.py", line 644, in provider_for
    raise UnknownProvider('couldn\'t determine provider for %r to %r' % (interface, to))
injector.UnknownProvider: couldn't determine provider for injector_test.test_inject_simple_generic_class.<locals>.GenericClass[str] to None

Could do with getting this one fixed soon-ish, and will be taking a look tomorrow to see if I can create a PR that fixes it. If you have any hints or tips that might help, it would be appreciated :)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with injector_test.py and reproduce test_inject_simple_generic_class on Python 3.7 or later. Trace the failure through injector/init.py, especially get_binding, create_binding, provider_for, and args_to_inject. Done means the generic-class injection test passes on the affected Python versions without breaking existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.