1
|
|
|
""" |
2
|
|
|
PRIVATE MODULE: do not import (from) it directly. |
3
|
|
|
|
4
|
|
|
This module contains the ``CallableMatcher``class. |
5
|
|
|
""" |
6
|
|
|
import inspect |
7
|
|
|
from typing import Callable, Tuple, Any, Awaitable |
8
|
|
|
from jacked._compatibility_impl import get_args_and_return_type |
9
|
|
|
from jacked._injectable import Injectable |
10
|
|
|
from jacked._container import Container |
11
|
|
|
from jacked._typing import NoneType, issubtype |
12
|
|
|
from jacked.matchers._base_matcher import BaseMatcher |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
class CallableMatcher(BaseMatcher): |
16
|
|
|
|
17
|
|
|
def match( |
18
|
|
|
self, |
19
|
|
|
hint: object, |
20
|
|
|
injectable: Injectable, |
21
|
|
|
container: Container): |
22
|
|
|
if inspect.isfunction(injectable.subject): |
23
|
|
|
params_hint, return_hint = get_args_and_return_type(hint) |
24
|
|
|
return_hint = (inspect.Signature.empty if return_hint is NoneType |
25
|
|
|
else return_hint) |
26
|
|
|
signature = inspect.signature(injectable.subject) |
27
|
|
|
params_injectable = tuple([signature.parameters[x].annotation |
28
|
|
|
for x in signature.parameters]) |
29
|
|
|
return_injectable = signature.return_annotation |
30
|
|
|
if inspect.iscoroutinefunction(injectable.subject): |
31
|
|
|
return_injectable = Awaitable[return_injectable] |
32
|
|
|
if (self._params_match(params_hint, params_injectable) |
33
|
|
|
and self._compatible_with(return_injectable, return_hint)): |
34
|
|
|
return injectable.subject |
35
|
|
|
|
36
|
|
|
def _matching_type(self): |
37
|
|
|
return Callable |
38
|
|
|
|
39
|
|
|
def _params_match(self, params_hint: Tuple[type, ...], |
40
|
|
|
params_injectable: Tuple[type, ...]) -> bool: |
41
|
|
|
if len(params_hint) != len(params_injectable): |
42
|
|
|
return False |
43
|
|
|
for i, _ in enumerate(params_hint): |
44
|
|
|
if not self._compatible_with(params_injectable[i], params_hint[i]): |
45
|
|
|
return False |
46
|
|
|
return True |
47
|
|
|
|
48
|
|
|
def _compatible_with(self, t1: type, t2: type): |
49
|
|
|
return t2 is Any or issubtype(t1, t2) |
50
|
|
|
|