77* Author(s): Dan Halbert, Michał Pokusa
88"""
99
10+ try :
11+ from typing import Callable , List , Union
12+ except ImportError :
13+ pass
14+
15+ import re
16+
1017from .methods import HTTPMethod
1118
1219
@@ -15,14 +22,66 @@ class _HTTPRoute:
1522
1623 def __init__ (self , path : str = "" , method : HTTPMethod = HTTPMethod .GET ) -> None :
1724
18- self .path = path
25+ contains_regex = re .search (r"<\w*>" , path )
26+
27+ self .path = path if not contains_regex else re .sub (r"<\w*>" , r"([^/]*)" , path )
1928 self .method = method
29+ self .regex = contains_regex
30+
31+ def matches (self , other : "_HTTPRoute" ) -> bool :
32+ """
33+ Checks if the route matches the other route.
34+
35+ If the route contains parameters, it will check if the other route contains values for them.
36+ """
2037
21- def __hash__ ( self ) -> int :
22- return hash (self .method ) ^ hash ( self .path )
38+ if self . regex or other . regex :
39+ return re . match (self .path , other . path ) and self .method == other . method
2340
24- def __eq__ (self , other : "_HTTPRoute" ) -> bool :
2541 return self .method == other .method and self .path == other .path
2642
2743 def __repr__ (self ) -> str :
2844 return f"HTTPRoute(path={ repr (self .path )} , method={ repr (self .method )} )"
45+
46+
47+ class _HTTPRoutes :
48+ """A collection of routes and their corresponding handlers."""
49+
50+ def __init__ (self ) -> None :
51+ self ._routes : List [_HTTPRoute ] = []
52+ self ._handlers : List [Callable ] = []
53+
54+ def add (self , route : _HTTPRoute , handler : Callable ):
55+ """Adds a route and its handler to the collection."""
56+
57+ self ._routes .append (route )
58+ self ._handlers .append (handler )
59+
60+ def find_handler (self , route : _HTTPRoute ) -> Union [Callable , None ]:
61+ """
62+ Finds a handler for a given route.
63+
64+ If route used URL parameters, the handler will be wrapped to pass the parameters to the
65+ handler.
66+
67+ Example::
68+
69+ @server.route("/example/<my_parameter>", HTTPMethod.GET)
70+ def route_func(request, my_parameter):
71+ ...
72+ request.path == "/example/123" # True
73+ my_parameter == "123" # True
74+ """
75+
76+ try :
77+ matched_route = next (filter (lambda r : r .matches (route ), self ._routes ))
78+ except StopIteration :
79+ return None
80+
81+ handler = self ._handlers [self ._routes .index (matched_route )]
82+ args = re .match (matched_route .path , route .path ).groups ()
83+
84+ def wrapper (request ):
85+ return handler (request , * args )
86+
87+ return wrapper
0 commit comments