Lancetnik / FastDepends

FastDepends - FastAPI Dependency Injection system extracted from FastAPI and cleared of all HTTP logic. Async and sync modes are both supported.
https://lancetnik.github.io/FastDepends/
MIT License
294 stars 11 forks source link

Using @inject on generator function raises `RuntimeError: generator didn't stop` #11

Closed chrisgoddard closed 1 year ago

chrisgoddard commented 1 year ago

In this mock example:

from fast_depends import Depends, inject

class Dependency:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return f"Dependency({self.name})"

def get_dependency():
    return Dependency("dependency")

@inject
def generator(
    d: Dependency = Depends(get_dependency),
):
    for i in range(10):
        yield i

When I then try to call and iterate on generator(), I get the following error:

----> [1](vscode-notebook-cell:/Users/chrisgoddard/Code/EdgePath/edgepath-pilot-core/notebooks/syntax.ipynb#W4sZmlsZQ%3D%3D?line=0) for x in generator():
      [2](vscode-notebook-cell:/Users/chrisgoddard/Code/EdgePath/edgepath-pilot-core/notebooks/syntax.ipynb#W4sZmlsZQ%3D%3D?line=1)     print(x)

File [/opt/homebrew/Caskroom/miniforge/base/envs/edgepath-pilot-core/lib/python3.11/site-packages/fast_depends/use.py:128](https://file+.vscode-resource.vscode-cdn.net/opt/homebrew/Caskroom/miniforge/base/envs/edgepath-pilot-core/lib/python3.11/site-packages/fast_depends/use.py:128), in _wrap_inject.<locals>.func_wrapper.<locals>.injected_wrapper(*args, **kwargs)
    126 @wraps(func)
    127 def injected_wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
--> 128     with ExitStack() as stack:
    129         r = real_model.solve(
    130             *args,
    131             stack=stack,
   (...)
    134             **kwargs,
    135         )
    136         return r

File [/opt/homebrew/Caskroom/miniforge/base/envs/edgepath-pilot-core/lib/python3.11/contextlib.py:589](https://file+.vscode-resource.vscode-cdn.net/opt/homebrew/Caskroom/miniforge/base/envs/edgepath-pilot-core/lib/python3.11/contextlib.py:589), in ExitStack.__exit__(self, *exc_details)
    585 try:
    586     # bare "raise exc_details[1]" replaces our carefully
    587     # set-up context
    588     fixed_ctx = exc_details[1].__context__
--> 589     raise exc_details[1]
    590 except BaseException:
    591     exc_details[1].__context__ = fixed_ctx

File [/opt/homebrew/Caskroom/miniforge/base/envs/edgepath-pilot-core/lib/python3.11/contextlib.py:574](https://file+.vscode-resource.vscode-cdn.net/opt/homebrew/Caskroom/miniforge/base/envs/edgepath-pilot-core/lib/python3.11/contextlib.py:574), in ExitStack.__exit__(self, *exc_details)
    572 assert is_sync
    573 try:
--> 574     if cb(*exc_details):
    575         suppressed_exc = True
    576         pending_raise = False

File [/opt/homebrew/Caskroom/miniforge/base/envs/edgepath-pilot-core/lib/python3.11/contextlib.py:148](https://file+.vscode-resource.vscode-cdn.net/opt/homebrew/Caskroom/miniforge/base/envs/edgepath-pilot-core/lib/python3.11/contextlib.py:148), in _GeneratorContextManager.__exit__(self, typ, value, traceback)
    146         return False
    147     else:
--> 148         raise RuntimeError("generator didn't stop")
    149 else:
    150     if value is None:
    151         # Need to force instantiation so we can reliably
    152         # tell if we get the same exception back

RuntimeError: generator didn't stop

I can see that there is logic in the CallModel class for is_generator but I'm not sure if there's something in how I write the generator or write the type hints that is the issue.

Lancetnik commented 1 year ago

@chrisgoddard thanks for the Issue! Created FastDepends I just forgot about yield function supporting. So, this feature is added in 2.2.0 release