8
8
"""
9
9
10
10
try :
11
- from typing import Callable , List , Union
11
+ from typing import Callable , List , Union , Tuple
12
12
except ImportError :
13
13
pass
14
14
@@ -22,41 +22,56 @@ class _HTTPRoute:
22
22
23
23
def __init__ (self , path : str = "" , method : HTTPMethod = HTTPMethod .GET ) -> None :
24
24
25
- contains_regex = re .search (r"<\w*>" , path ) is not None
25
+ contains_parameters = re .search (r"<\w*>" , path ) is not None
26
26
27
- self .path = path if not contains_regex else re .sub (r"<\w*>" , r"([^/]*)" , path )
27
+ self .path = (
28
+ path if not contains_parameters else re .sub (r"<\w*>" , r"([^/]*)" , path )
29
+ )
28
30
self .method = method
29
- self ._contains_regex = contains_regex
30
- self ._last_match_groups : Union [List [str ], None ] = None
31
+ self ._contains_parameters = contains_parameters
31
32
32
- def matches (self , other : "_HTTPRoute" ) -> bool :
33
+ def match (self , other : "_HTTPRoute" ) -> Tuple [ bool , List [ str ]] :
33
34
"""
34
35
Checks if the route matches the other route.
35
36
36
37
If the route contains parameters, it will check if the ``other`` route contains values for
37
38
them.
39
+
40
+ Returns tuple of a boolean and a list of strings. The boolean indicates if the routes match,
41
+ and the list contains the values of the url parameters from the ``other`` route.
42
+
43
+ Examples::
44
+
45
+ route = _HTTPRoute("/example", HTTPMethod.GET)
46
+
47
+ other1 = _HTTPRoute("/example", HTTPMethod.GET)
48
+ route.matches(other1) # True, []
49
+
50
+ other2 = _HTTPRoute("/other-example", HTTPMethod.GET)
51
+ route.matches(other2) # False, []
52
+
53
+ ...
54
+
55
+ route = _HTTPRoute("/example/<parameter>", HTTPMethod.GET)
56
+
57
+ other1 = _HTTPRoute("/example/123", HTTPMethod.GET)
58
+ route.matches(other1) # True, ["123"]
59
+
60
+ other2 = _HTTPRoute("/other-example", HTTPMethod.GET)
61
+ route.matches(other2) # False, []
38
62
"""
63
+
39
64
if self .method != other .method :
40
- return False
65
+ return False , []
41
66
42
- if not self ._contains_regex :
43
- return self .path == other .path
67
+ if not self ._contains_parameters :
68
+ return self .path == other .path , []
44
69
45
70
regex_match = re .match (self .path , other .path )
46
71
if regex_match is None :
47
- return False
48
-
49
- self ._last_match_groups = regex_match .groups ()
50
- return True
51
-
52
- def last_match_groups (self ) -> Union [List [str ], None ]:
53
- """
54
- Returns the last match groups from the last call to `matches`.
72
+ return False , []
55
73
56
- Useful for getting the values of the parameters from the route, without the need to call
57
- `re.match` again.
58
- """
59
- return self ._last_match_groups
74
+ return True , regex_match .groups ()
60
75
61
76
def __repr__ (self ) -> str :
62
77
return f"_HTTPRoute(path={ repr (self .path )} , method={ repr (self .method )} )"
@@ -90,19 +105,27 @@ def route_func(request, my_parameter):
90
105
request.path == "/example/123" # True
91
106
my_parameter == "123" # True
92
107
"""
108
+ if not self ._routes :
109
+ raise ValueError ("No routes added" )
110
+
111
+ found_route , _route = False , None
112
+
113
+ for _route in self ._routes :
114
+ matches , url_parameters_values = _route .match (route )
115
+
116
+ if matches :
117
+ found_route = True
118
+ break
93
119
94
- try :
95
- matched_route = next (filter (lambda r : r .matches (route ), self ._routes ))
96
- except StopIteration :
120
+ if not found_route :
97
121
return None
98
122
99
- handler = self ._handlers [self ._routes .index (matched_route )]
100
- args = matched_route .last_match_groups () or []
123
+ handler = self ._handlers [self ._routes .index (_route )]
101
124
102
- def wrapper (request ):
103
- return handler (request , * args )
125
+ def wrapped_handler (request ):
126
+ return handler (request , * url_parameters_values )
104
127
105
- return wrapper
128
+ return wrapped_handler
106
129
107
130
def __repr__ (self ) -> str :
108
131
return f"_HTTPRoutes({ repr (self ._routes )} )"
0 commit comments