88"""
99
1010try :
11- from typing import Callable , List , Union
11+ from typing import Callable , List , Union , Tuple
1212except ImportError :
1313 pass
1414
@@ -22,41 +22,56 @@ class _HTTPRoute:
2222
2323 def __init__ (self , path : str = "" , method : HTTPMethod = HTTPMethod .GET ) -> None :
2424
25- contains_regex = re .search (r"<\w*>" , path ) is not None
25+ contains_parameters = re .search (r"<\w*>" , path ) is not None
2626
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+ )
2830 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
3132
32- def matches (self , other : "_HTTPRoute" ) -> bool :
33+ def match (self , other : "_HTTPRoute" ) -> Tuple [ bool , List [ str ]] :
3334 """
3435 Checks if the route matches the other route.
3536
3637 If the route contains parameters, it will check if the ``other`` route contains values for
3738 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, []
3862 """
63+
3964 if self .method != other .method :
40- return False
65+ return False , []
4166
42- if not self ._contains_regex :
43- return self .path == other .path
67+ if not self ._contains_parameters :
68+ return self .path == other .path , []
4469
4570 regex_match = re .match (self .path , other .path )
4671 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 , []
5573
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 ()
6075
6176 def __repr__ (self ) -> str :
6277 return f"_HTTPRoute(path={ repr (self .path )} , method={ repr (self .method )} )"
@@ -90,19 +105,27 @@ def route_func(request, my_parameter):
90105 request.path == "/example/123" # True
91106 my_parameter == "123" # True
92107 """
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
93119
94- try :
95- matched_route = next (filter (lambda r : r .matches (route ), self ._routes ))
96- except StopIteration :
120+ if not found_route :
97121 return None
98122
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 )]
101124
102- def wrapper (request ):
103- return handler (request , * args )
125+ def wrapped_handler (request ):
126+ return handler (request , * url_parameters_values )
104127
105- return wrapper
128+ return wrapped_handler
106129
107130 def __repr__ (self ) -> str :
108131 return f"_HTTPRoutes({ repr (self ._routes )} )"
0 commit comments