Skip to content

CallModel

autogen.fast_depends.core.model.CallModel #

CallModel(call, model, params, response_model=None, use_cache=True, cast=True, is_async=False, is_generator=False, dependencies=None, extra_dependencies=None, keyword_args=None, positional_args=None, var_positional_arg=None, var_keyword_arg=None, custom_fields=None)

Bases: Generic[P, T]

Source code in autogen/fast_depends/core/model.py
def __init__(
    self,
    /,
    call: Union[
        Callable[P, T],
        Callable[P, Awaitable[T]],
    ],
    model: Optional[Type[BaseModel]],
    params: Dict[str, Tuple[Any, Any]],
    response_model: Optional[Type[ResponseModel[T]]] = None,
    use_cache: bool = True,
    cast: bool = True,
    is_async: bool = False,
    is_generator: bool = False,
    dependencies: Optional[Dict[str, "CallModel[..., Any]"]] = None,
    extra_dependencies: Optional[Iterable["CallModel[..., Any]"]] = None,
    keyword_args: Optional[List[str]] = None,
    positional_args: Optional[List[str]] = None,
    var_positional_arg: Optional[str] = None,
    var_keyword_arg: Optional[str] = None,
    custom_fields: Optional[Dict[str, CustomField]] = None,
):
    self.call = call
    self.model = model

    if model:
        self.alias_arguments = get_aliases(model)
    else:  # pragma: no cover
        self.alias_arguments = ()

    self.keyword_args = tuple(keyword_args or ())
    self.positional_args = tuple(positional_args or ())
    self.var_positional_arg = var_positional_arg
    self.var_keyword_arg = var_keyword_arg
    self.response_model = response_model
    self.use_cache = use_cache
    self.cast = cast
    self.is_async = is_async or is_coroutine_callable(call) or is_async_gen_callable(call)
    self.is_generator = is_generator or is_gen_callable(call) or is_async_gen_callable(call)

    self.dependencies = dependencies or {}
    self.extra_dependencies = extra_dependencies or ()
    self.custom_fields = custom_fields or {}

    sorted_dep: List[CallModel[..., Any]] = []
    flat = self.flat_dependencies
    for calls in flat.values():
        _sort_dep(sorted_dep, calls, flat)

    self.sorted_dependencies = tuple((i, len(i.sorted_dependencies)) for i in sorted_dep if i.use_cache)
    for name in chain(self.dependencies.keys(), self.custom_fields.keys()):
        params.pop(name, None)
    self.params = params

alias_arguments instance-attribute #

alias_arguments

call_name property #

call_name

flat_params property #

flat_params

flat_dependencies property #

flat_dependencies

call instance-attribute #

call = call

model instance-attribute #

model = model

keyword_args instance-attribute #

keyword_args = tuple(keyword_args or ())

positional_args instance-attribute #

positional_args = tuple(positional_args or ())

var_positional_arg instance-attribute #

var_positional_arg = var_positional_arg

var_keyword_arg instance-attribute #

var_keyword_arg = var_keyword_arg

response_model instance-attribute #

response_model = response_model

use_cache instance-attribute #

use_cache = use_cache

cast instance-attribute #

cast = cast

is_async instance-attribute #

is_async = is_async or is_coroutine_callable(call) or is_async_gen_callable(call)

is_generator instance-attribute #

is_generator = is_generator or is_gen_callable(call) or is_async_gen_callable(call)

dependencies instance-attribute #

dependencies = dependencies or {}

extra_dependencies instance-attribute #

extra_dependencies = extra_dependencies or ()

custom_fields instance-attribute #

custom_fields = custom_fields or {}

sorted_dependencies instance-attribute #

sorted_dependencies = tuple((i, len(sorted_dependencies)) for i in sorted_dep if use_cache)

params instance-attribute #

params = params

solve #

solve(*args, stack, cache_dependencies, dependency_overrides=None, nested=False, **kwargs)
Source code in autogen/fast_depends/core/model.py
def solve(
    self,
    /,
    *args: Any,
    stack: ExitStack,
    cache_dependencies: Dict[
        Union[
            Callable[P, T],
            Callable[P, Awaitable[T]],
        ],
        T,
    ],
    dependency_overrides: Optional[
        Dict[
            Union[
                Callable[P, T],
                Callable[P, Awaitable[T]],
            ],
            Union[
                Callable[P, T],
                Callable[P, Awaitable[T]],
            ],
        ]
    ] = None,
    nested: bool = False,
    **kwargs: Any,
) -> T:
    cast_gen = self._solve(
        *args,
        cache_dependencies=cache_dependencies,
        dependency_overrides=dependency_overrides,
        **kwargs,
    )
    try:
        args, kwargs, _ = next(cast_gen)  # type: ignore[assignment]
    except StopIteration as e:
        cached_value: T = e.value
        return cached_value

    # Heat cache and solve extra dependencies
    for dep, _ in self.sorted_dependencies:
        dep.solve(
            *args,
            stack=stack,
            cache_dependencies=cache_dependencies,
            dependency_overrides=dependency_overrides,
            nested=True,
            **kwargs,
        )

    # Always get from cache
    for dep in self.extra_dependencies:
        dep.solve(
            *args,
            stack=stack,
            cache_dependencies=cache_dependencies,
            dependency_overrides=dependency_overrides,
            nested=True,
            **kwargs,
        )

    for dep_arg, dep in self.dependencies.items():
        kwargs[dep_arg] = dep.solve(
            stack=stack,
            cache_dependencies=cache_dependencies,
            dependency_overrides=dependency_overrides,
            nested=True,
            **kwargs,
        )

    for custom in self.custom_fields.values():
        if custom.field:
            custom.use_field(kwargs)
        else:
            kwargs = custom.use(**kwargs)

    final_args, final_kwargs, call = cast_gen.send(kwargs)

    if self.is_generator and nested:
        response = solve_generator_sync(
            *final_args,
            call=call,
            stack=stack,
            **final_kwargs,
        )

    else:
        response = call(*final_args, **final_kwargs)

    try:
        cast_gen.send(response)
    except StopIteration as e:
        value: T = e.value

        if not self.cast or nested or not self.is_generator:
            return value

        else:
            return map(self._cast_response, value)  # type: ignore[no-any-return, call-overload]

    raise AssertionError("unreachable")

asolve async #

asolve(*args, stack, cache_dependencies, dependency_overrides=None, nested=False, **kwargs)
Source code in autogen/fast_depends/core/model.py
async def asolve(
    self,
    /,
    *args: Any,
    stack: AsyncExitStack,
    cache_dependencies: Dict[
        Union[
            Callable[P, T],
            Callable[P, Awaitable[T]],
        ],
        T,
    ],
    dependency_overrides: Optional[
        Dict[
            Union[
                Callable[P, T],
                Callable[P, Awaitable[T]],
            ],
            Union[
                Callable[P, T],
                Callable[P, Awaitable[T]],
            ],
        ]
    ] = None,
    nested: bool = False,
    **kwargs: Any,
) -> T:
    cast_gen = self._solve(
        *args,
        cache_dependencies=cache_dependencies,
        dependency_overrides=dependency_overrides,
        **kwargs,
    )
    try:
        args, kwargs, _ = next(cast_gen)  # type: ignore[assignment]
    except StopIteration as e:
        cached_value: T = e.value
        return cached_value

    # Heat cache and solve extra dependencies
    dep_to_solve: List[Callable[..., Awaitable[Any]]] = []
    try:
        async with anyio.create_task_group() as tg:
            for dep, subdep in self.sorted_dependencies:
                solve = partial(
                    dep.asolve,
                    *args,
                    stack=stack,
                    cache_dependencies=cache_dependencies,
                    dependency_overrides=dependency_overrides,
                    nested=True,
                    **kwargs,
                )
                if not subdep:
                    tg.start_soon(solve)
                else:
                    dep_to_solve.append(solve)
    except ExceptionGroup as exgr:
        for ex in exgr.exceptions:
            raise ex from None

    for i in dep_to_solve:
        await i()

    # Always get from cache
    for dep in self.extra_dependencies:
        await dep.asolve(
            *args,
            stack=stack,
            cache_dependencies=cache_dependencies,
            dependency_overrides=dependency_overrides,
            nested=True,
            **kwargs,
        )

    for dep_arg, dep in self.dependencies.items():
        kwargs[dep_arg] = await dep.asolve(
            stack=stack,
            cache_dependencies=cache_dependencies,
            dependency_overrides=dependency_overrides,
            nested=True,
            **kwargs,
        )

    custom_to_solve: List[CustomField] = []

    try:
        async with anyio.create_task_group() as tg:
            for custom in self.custom_fields.values():
                if custom.field:
                    tg.start_soon(run_async, custom.use_field, kwargs)
                else:
                    custom_to_solve.append(custom)

    except ExceptionGroup as exgr:
        for ex in exgr.exceptions:
            raise ex from None

    for j in custom_to_solve:
        kwargs = await run_async(j.use, **kwargs)

    final_args, final_kwargs, call = cast_gen.send(kwargs)

    if self.is_generator and nested:
        response = await solve_generator_async(
            *final_args,
            call=call,
            stack=stack,
            **final_kwargs,
        )
    else:
        response = await run_async(call, *final_args, **final_kwargs)

    try:
        cast_gen.send(response)
    except StopIteration as e:
        value: T = e.value

        if not self.cast or nested or not self.is_generator:
            return value

        else:
            return async_map(self._cast_response, value)  # type: ignore[return-value, arg-type]

    raise AssertionError("unreachable")