kodemore / kink

Dependency injection container made for Python
MIT License
397 stars 25 forks source link

Fix injection with cache wrapper against pydantic object #61

Open moria97 opened 1 month ago

moria97 commented 1 month ago

When I use following code, there is a signature issue with cache wrappers on pydantic objects.

from kink import inject, di
from pydantic import BaseModel
import functools

@inject
@functools.cache
class A(BaseModel):
    name: str = None

    def __init__(self, name):
        super().__init__()
        self.name = name
        print("Create A", name)

    __hash__ = object.__hash__

@inject
@functools.cache
class B:
    def __init__(self, a:A):
        self.name = f"Mr {a.name}"
        print("Create B", a.name)

di["name"] = "Dudu"
di.factories["a"] = lambda di: A()
di.factories[B] = lambda di: B()

b = di[B]

Error logs

    @inject
     ^^^^^^
  File "/opt/miniconda3/envs/rag/lib/python3.11/site-packages/kink/inject.py", line 203, in inject
    return _decorator(_service)
           ^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/rag/lib/python3.11/site-packages/kink/inject.py", line 194, in _decorator
    service_function = _decorate(bind or {}, _service, container)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/rag/lib/python3.11/site-packages/kink/inject.py", line 111, in _decorate
    parameters_name, parameters = _inspect_function_arguments(service)
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/rag/lib/python3.11/site-packages/kink/inject.py", line 56, in _inspect_function_arguments
    parameters_name: Tuple[str, ...] = tuple(signature(function).parameters.keys())
                                             ^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/rag/lib/python3.11/inspect.py", line 3263, in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/rag/lib/python3.11/inspect.py", line 3011, in from_callable
    return _signature_from_callable(obj, sigcls=cls,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/rag/lib/python3.11/inspect.py", line 2487, in _signature_from_callable
    raise TypeError(
TypeError: unexpected object <pydantic._internal._utils.ClassAttribute object at 0x169030bb0> in __signature__ attribute