-
-
Notifications
You must be signed in to change notification settings - Fork 471
/
Copy pathutils.py
96 lines (67 loc) · 2.84 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import asyncio
import inspect
import re
import sys
from typing import Any, Callable, ForwardRef, List, Set, cast
from django.urls import register_converter
from django.urls.converters import UUIDConverter
if sys.version_info < (3, 9): # pragma: nocover
def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
return type_._evaluate(globalns, localns)
else:
def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
# Even though it is the right signature for python 3.9, mypy complains with
# `error: Too many arguments for "_evaluate" of "ForwardRef"` hence the cast...
return cast(Any, type_)._evaluate(globalns, localns, recursive_guard=set())
from ninja.types import DictStrAny
__all__ = [
"get_typed_signature",
"get_typed_annotation",
"make_forwardref",
"get_path_param_names",
"is_async",
]
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
"Finds call signature and resolves all forwardrefs"
signature = inspect.signature(call)
globalns = getattr(call, "__globals__", {})
typed_params = [
inspect.Parameter(
name=param.name,
kind=param.kind,
default=param.default,
annotation=get_typed_annotation(param, globalns),
)
for param in signature.parameters.values()
]
typed_signature = inspect.Signature(typed_params)
return typed_signature
def get_typed_annotation(param: inspect.Parameter, globalns: DictStrAny) -> Any:
annotation = param.annotation
if isinstance(annotation, str):
annotation = make_forwardref(annotation, globalns)
return annotation
def make_forwardref(annotation: str, globalns: DictStrAny) -> Any:
forward_ref = ForwardRef(annotation)
return evaluate_forwardref(forward_ref, globalns, globalns)
def get_path_param_names(path: str) -> Set[str]:
"""turns path string like /foo/{var}/path/{int:another}/end to set {'var', 'another'}"""
return {item.strip("{}").split(":")[-1] for item in re.findall("{[^}]*}", path)}
def is_async(callable: Callable[..., Any]) -> bool:
return asyncio.iscoroutinefunction(callable)
def has_kwargs(func: Callable[..., Any]) -> bool:
for param in inspect.signature(func).parameters.values():
if param.kind == param.VAR_KEYWORD:
return True
return False
def get_args_names(func: Callable[..., Any]) -> List[str]:
"returns list of function argument names"
return list(inspect.signature(func).parameters.keys())
class NinjaUUIDConverter:
"""Return a path converted UUID as a str instead of the standard UUID"""
regex = UUIDConverter.regex
def to_python(self, value: str) -> str:
return value
def to_url(self, value: Any) -> str:
return str(value)
register_converter(NinjaUUIDConverter, "uuid")