|
5 | 5 | from wsgiref.headers import Headers
|
6 | 6 | import pathlib
|
7 | 7 | import urllib.parse
|
| 8 | +from collections.abc import Iterable |
8 | 9 |
|
9 | 10 | import traceback
|
10 | 11 | import mimetypes
|
|
38 | 39 | REVERSE_ROUTE_INFO = {}
|
39 | 40 | PROJECT_MASK = 'PROJECT_MASK_PATH'
|
40 | 41 |
|
41 |
| -def reverse(name_path:str, args=None, kwargs=None) -> str: |
| 42 | +def reverse(name_path:str, *args, **kwargs) -> str: |
42 | 43 | if not isinstance(name_path, str) or not re.match(r"^[^\d\W][\w-]*\Z", name_path):
|
43 | 44 | raise ValueError("Name path must but a valid identifier name.")
|
44 |
| - args = args or {} |
45 |
| - kwargs = kwargs or {} |
| 45 | + |
| 46 | + args = kwargs.get('args') or args or {} |
| 47 | + kwargs.pop('args', None) |
| 48 | + kwargs = kwargs.get('kwargs') or kwargs or {} |
| 49 | + |
46 | 50 | if args and kwargs:
|
47 |
| - raise ValueError(("Don't use *args and **kwargs." |
48 |
| - "*args is for get and **kwargs for post method.")) |
49 |
| - path = REVERSE_ROUTE_INFO.get(name_path) |
| 51 | + raise ValueError(("You can't mix *args and **kwargs.")) |
| 52 | + if not isinstance(args, Iterable) or not isinstance(kwargs, dict): |
| 53 | + raise ValueError("*args or ** kwargs must be list and dict respectively") |
| 54 | + |
| 55 | + path, view = REVERSE_ROUTE_INFO.get(name_path) or (None, None) |
| 56 | + original_path = path |
50 | 57 | if not path:
|
51 | 58 | raise NoReverseFound(f"Reverse for {name_path} not found.")
|
52 |
| - |
| 59 | + regex = r'<(?:(?P<converter>[^>:]+):)?(?P<parameter>[^>]+)>' |
| 60 | + url = re.compile(regex, 0) |
| 61 | + params_path = list(url.finditer(path)) |
| 62 | + got_params = args or kwargs |
| 63 | + if len(params_path) != len(got_params): |
| 64 | + raise ValueError((f"The view `{view}` expects {len(params_path)} " |
| 65 | + f"parameters but has received {len(got_params)}")) |
53 | 66 | if args:
|
54 |
| - path = path +'?'+ urllib.parse.urlencode(args) |
| 67 | + for arg, match in zip(args, params_path): |
| 68 | + path = re.sub( |
| 69 | + original_path[match.start():match.end()], |
| 70 | + urllib.parse.quote(str(arg)), |
| 71 | + path |
| 72 | + ) |
55 | 73 | else:
|
56 |
| - regex = r'<(?:(?P<converter>[^>:]+):)?(?P<parameter>[^>]+)>' |
57 |
| - url = re.compile(regex, 0) |
58 |
| - helper_path = path |
59 |
| - for match in url.finditer(path): |
| 74 | + for match in params_path: |
60 | 75 | value = kwargs.get(match['parameter'])
|
61 | 76 | if not value:
|
62 |
| - raise NoReverseFound((f"Reverse for {name_path} not found. " |
| 77 | + raise NoReverseFound((f"Reverse for `{name_path}` not found. " |
63 | 78 | "Keyword arguments '%s' not found." % match['parameter']))
|
64 | 79 | path = re.sub(
|
65 |
| - helper_path[match.start():match.end()], |
66 |
| - str(value), |
| 80 | + original_path[match.start():match.end()], |
| 81 | + urllib.parse.quote(str(value)), |
67 | 82 | path
|
68 | 83 | )
|
69 |
| - return path |
| 84 | + return path |
70 | 85 |
|
71 | 86 | def load_static(value):
|
72 | 87 | return os.path.join('/staticfiles/', value)
|
@@ -125,7 +140,7 @@ def request_response_application(callback):
|
125 | 140 | ROUTES[new_path] = (callback, converters, path, methods)
|
126 | 141 |
|
127 | 142 | # if: pass
|
128 |
| - REVERSE_ROUTE_INFO[name or callback.__name__] = path |
| 143 | + REVERSE_ROUTE_INFO[name or callback.__name__] = path, callback.__name__ |
129 | 144 | def application(environ, start_response):
|
130 | 145 | request = Request(environ)
|
131 | 146 | #authorized
|
|
0 commit comments