Skip to content

Commit

Permalink
Use globals of original(wrapped) function (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahnjaeshin authored Jun 5, 2024
1 parent a936df9 commit 5585390
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 5 deletions.
12 changes: 7 additions & 5 deletions fast_depends/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ def get_typed_signature(call: Callable[..., Any]) -> Tuple[inspect.Signature, An

locals = collect_outer_stack_locals()

# We unwrap call to get the original unwrapped function
call = inspect.unwrap(call)

globalns = getattr(call, "__globals__", {})
typed_params = [
inspect.Parameter(
Expand Down Expand Up @@ -129,12 +132,11 @@ def get_typed_annotation(
if isinstance(annotation, ForwardRef):
annotation = evaluate_forwardref(annotation, globalns, locals)

if (
get_origin(annotation) is Annotated
and (args := get_args(annotation))
):
if get_origin(annotation) is Annotated and (args := get_args(annotation)):
solved_args = [get_typed_annotation(x, globalns, locals) for x in args]
annotation.__origin__, annotation.__metadata__ = solved_args[0], tuple(solved_args[1:])
annotation.__origin__, annotation.__metadata__ = solved_args[0], tuple(
solved_args[1:]
)

return annotation

Expand Down
Empty file added tests/__init__.py
Empty file.
32 changes: 32 additions & 0 deletions tests/test_prebuild.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
from __future__ import annotations

from fast_depends.core import build_call_model
from fast_depends.use import inject

from .wrapper import noop_wrap

from pydantic import BaseModel


class Model(BaseModel):
a: str


def base_func(a: int) -> str:
return "success"


def model_func(m: Model) -> str:
return m.a


def test_prebuild():
model = build_call_model(base_func)
inject()(None, model)(1)


def test_prebuild_with_wrapper():
func = noop_wrap(model_func)
assert func(Model(a="Hi!")) == "Hi!"

# build_call_model should work even if function is wrapped with a
# wrapper that is imported from different module
call_model = build_call_model(func)

assert call_model.model
# Fails if function unwrapping is not done at type introspection

if hasattr(call_model.model, "model_rebuild"):
call_model.model.model_rebuild()
else:
# pydantic v1
call_model.model.update_forward_refs()
11 changes: 11 additions & 0 deletions tests/wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from __future__ import annotations

from functools import wraps


def noop_wrap(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)

return wrapper

0 comments on commit 5585390

Please sign in to comment.