88"""
99
1010try :
11- from typing import Callable , List , Iterable , Union , Tuple , Dict , TYPE_CHECKING
11+ from typing import Callable , Iterable , Union , Tuple , Literal , Dict , TYPE_CHECKING
1212
1313 if TYPE_CHECKING :
1414 from .response import Response
@@ -36,13 +36,18 @@ def __init__(
3636 self .parameters_names = [
3737 name [1 :- 1 ] for name in re .compile (r"/[^<>]*/?" ).split (path ) if name != ""
3838 ]
39- self .path = re .sub (r"<\w+>" , r"([^/]+)" , path ).replace ("...." , r".+" ).replace (
40- "..." , r"[^/]+"
41- ) + ("/?" if append_slash else "" )
39+ self .path_pattern = re .compile (
40+ r"^"
41+ + re .sub (r"<\w+>" , r"([^/]+)" , path )
42+ .replace (r"...." , r".+" )
43+ .replace (r"..." , r"[^/]+" )
44+ + (r"/?" if append_slash else r"" )
45+ + r"$"
46+ )
47+ self .path = path
4248 self .methods = (
4349 set (methods ) if isinstance (methods , (set , list , tuple )) else set ([methods ])
4450 )
45-
4651 self .handler = handler
4752
4853 @staticmethod
@@ -56,7 +61,9 @@ def _validate_path(path: str, append_slash: bool) -> None:
5661 if path .endswith ("/" ) and append_slash :
5762 raise ValueError ("Cannot use append_slash=True when path ends with /" )
5863
59- def match (self , other : "Route" ) -> Tuple [bool , Dict [str , str ]]:
64+ def matches (
65+ self , method : str , path : str
66+ ) -> Union [Tuple [Literal [False ], None ], Tuple [Literal [True ], Dict [str , str ]]]:
6067 """
6168 Checks if the route matches the other route.
6269
@@ -68,45 +75,41 @@ def match(self, other: "Route") -> Tuple[bool, Dict[str, str]]:
6875
6976 Examples::
7077
71- route = Route("/example", GET, True)
78+ route = Route("/example", GET, append_slash= True)
7279
73- other1a = Route("/example", GET)
74- other1b = Route("/example/", GET)
75- route.matches(other1a) # True, {}
76- route.matches(other1b) # True, {}
80+ route.matches(GET, "/example") # True, {}
81+ route.matches(GET, "/example/") # True, {}
7782
78- other2 = Route( "/other-example", GET)
79- route.matches(other2 ) # False, {}
83+ route.matches(GET, "/other-example") # False, None
84+ route.matches(POST, "/example/" ) # False, None
8085
8186 ...
8287
8388 route = Route("/example/<parameter>", GET)
8489
85- other1 = Route("/example/123", GET)
86- route.matches(other1) # True, {"parameter": "123"}
90+ route.matches(GET, "/example/123") # True, {"parameter": "123"}
8791
88- other2 = Route("/other-example", GET)
89- route.matches(other2) # False, {}
92+ route.matches(GET, "/other-example") # False, None
9093
9194 ...
9295
93- route1 = Route("/example/.../something", GET)
94- other1 = Route("/example/123/something", GET)
95- route1.matches(other1) # True, {}
96+ route = Route("/example/.../something", GET)
97+ route.matches(GET, "/example/123/something") # True, {}
9698
97- route2 = Route("/example/..../something", GET)
98- other2 = Route("/example/123/456/something", GET)
99- route2.matches(other2) # True, {}
99+ route = Route("/example/..../something", GET)
100+ route.matches(GET, "/example/123/456/something") # True, {}
100101 """
101102
102- if not other .methods .issubset (self .methods ):
103- return False , {}
103+ if method not in self .methods :
104+ return False , None
105+
106+ path_match = self .path_pattern .match (path )
107+ if path_match is None :
108+ return False , None
104109
105- regex_match = re .match (f"^{ self .path } $" , other .path )
106- if regex_match is None :
107- return False , {}
110+ url_parameters_values = path_match .groups ()
108111
109- return True , dict (zip (self .parameters_names , regex_match . groups () ))
112+ return True , dict (zip (self .parameters_names , url_parameters_values ))
110113
111114 def __repr__ (self ) -> str :
112115 path = repr (self .path )
@@ -168,51 +171,3 @@ def route_decorator(func: Callable) -> Route:
168171 return Route (path , methods , func , append_slash = append_slash )
169172
170173 return route_decorator
171-
172-
173- class _Routes :
174- """A collection of routes and their corresponding handlers."""
175-
176- def __init__ (self ) -> None :
177- self ._routes : List [Route ] = []
178-
179- def add (self , route : Route ):
180- """Adds a route and its handler to the collection."""
181- self ._routes .append (route )
182-
183- def find_handler (self , route : Route ) -> Union [Callable ["..." , "Response" ], None ]:
184- """
185- Finds a handler for a given route.
186-
187- If route used URL parameters, the handler will be wrapped to pass the parameters to the
188- handler.
189-
190- Example::
191-
192- @server.route("/example/<my_parameter>", GET)
193- def route_func(request, my_parameter):
194- ...
195- request.path == "/example/123" # True
196- my_parameter == "123" # True
197- """
198- found_route , _route = False , None
199-
200- for _route in self ._routes :
201- matches , keyword_parameters = _route .match (route )
202-
203- if matches :
204- found_route = True
205- break
206-
207- if not found_route :
208- return None
209-
210- handler = _route .handler
211-
212- def wrapped_handler (request ):
213- return handler (request , ** keyword_parameters )
214-
215- return wrapped_handler
216-
217- def __repr__ (self ) -> str :
218- return f"_Routes({ repr (self ._routes )} )"
0 commit comments