11import re
22import typing as t
3- from collections import defaultdict , namedtuple
3+ from collections import namedtuple
44from types import SimpleNamespace
55
6- from .exceptions import InvalidUsage , ParameterNameConflicts , RouteExists
6+ from .exceptions import InvalidUsage , ParameterNameConflicts
77from .patterns import REGEX_TYPES
88from .utils import Immutable , parts_to_path , path_to_parts
99
1212)
1313
1414
15- class Requirements (dict ):
15+ class Requirements (Immutable ):
1616 def __hash__ (self ):
1717 return hash (frozenset (self .items ()))
1818
@@ -22,10 +22,11 @@ class Route:
2222 "_params" ,
2323 "_raw_path" ,
2424 "ctx" ,
25- "handlers " ,
25+ "handler " ,
2626 "labels" ,
2727 "methods" ,
2828 "name" ,
29+ "overloaded" ,
2930 "params" ,
3031 "parts" ,
3132 "path" ,
@@ -36,14 +37,16 @@ class Route:
3637 "static" ,
3738 "strict" ,
3839 "unquote" ,
39- "overloaded" ,
4040 )
4141
4242 def __init__ (
4343 self ,
4444 router ,
4545 raw_path : str ,
4646 name : str ,
47+ handler : t .Callable [..., t .Any ],
48+ methods : t .Iterable [str ],
49+ requirements : t .Dict [str , t .Any ] = None ,
4750 strict : bool = False ,
4851 unquote : bool = False ,
4952 static : bool = False ,
@@ -52,10 +55,14 @@ def __init__(
5255 ):
5356 self .router = router
5457 self .name = name
55- self .handlers = defaultdict (lambda : defaultdict (list )) # type: ignore
58+ self .handler = handler
59+ self .methods = frozenset (methods )
60+ self .requirements = Requirements (requirements or {})
61+
62+ self .ctx = SimpleNamespace ()
63+
5664 self ._params : t .Dict [int , ParamInfo ] = {}
5765 self ._raw_path = raw_path
58- self .ctx = SimpleNamespace ()
5966
6067 parts = path_to_parts (raw_path , self .router .delimiter )
6168 self .path = parts_to_path (parts , delimiter = self .router .delimiter )
@@ -66,64 +73,42 @@ def __init__(
6673 self .pattern = None
6774 self .strict : bool = strict
6875 self .unquote : bool = unquote
69- self .requirements : t .Dict [int , t .Any ] = {}
7076 self .labels : t .Optional [t .List [str ]] = None
7177
72- def __repr__ (self ):
78+ self ._setup_params ()
79+
80+ def __str__ (self ):
7381 display = (
7482 f"name={ self .name } path={ self .path or self .router .delimiter } "
7583 if self .name and self .name != self .path
7684 else f"path={ self .path or self .router .delimiter } "
7785 )
7886 return f"<{ self .__class__ .__name__ } : { display } >"
7987
80- def get_handler (self , raw_path , method , idx ):
81- method = method or self .router .DEFAULT_METHOD
82- raw_path = raw_path .lstrip (self .router .delimiter )
83- try :
84- return self .handlers [raw_path ][method ][idx ]
85- except (IndexError , KeyError ):
86- raise self .router .method_handler_exception (
87- f"Method '{ method } ' not found on { self } " ,
88- method = method ,
89- allowed_methods = self .methods ,
88+ def __eq__ (self , other ) -> bool :
89+ if not isinstance (other , self .__class__ ):
90+ return False
91+ return bool (
92+ (
93+ self .parts ,
94+ self .requirements ,
95+ )
96+ == (
97+ other .parts ,
98+ other .requirements ,
9099 )
100+ and (self .methods & other .methods )
101+ )
91102
92- def add_handler (
93- self ,
94- raw_path ,
95- handler ,
96- method ,
97- requirements ,
98- overwrite : bool = False ,
99- ):
103+ def _setup_params (self ):
100104 key_path = parts_to_path (
101- path_to_parts (raw_path , self .router .delimiter ),
105+ path_to_parts (self . raw_path , self .router .delimiter ),
102106 self .router .delimiter ,
103107 )
104-
105- if (
106- not self .router .stacking
107- and self .handlers .get (key_path , {}).get (method )
108- and (
109- requirements is None
110- or Requirements (requirements ) in self .requirements .values ()
111- )
112- and not overwrite
113- ):
114- raise RouteExists (
115- f"Route already registered: { key_path } [{ method } ]"
116- )
117-
118- idx = len (self .handlers [key_path ][method .upper ()])
119- self .handlers [key_path ][method .upper ()].append (handler )
120- if requirements is not None :
121- self .requirements [idx ] = Requirements (requirements )
122-
123108 if not self .static :
124109 parts = path_to_parts (key_path , self .router .delimiter )
125110 for idx , part in enumerate (parts ):
126- if "<" in part and len ( self . handlers [ key_path ]) == 1 :
111+ if "<" in part :
127112 if ":" in part :
128113 (
129114 name ,
@@ -173,17 +158,6 @@ def _finalize_params(self):
173158 sorted (params .items (), key = lambda param : self ._sorting (param [1 ]))
174159 )
175160
176- def _finalize_methods (self ):
177- self .methods = set ()
178- for handlers in self .handlers .values ():
179- self .methods .update (set (key .upper () for key in handlers .keys ()))
180-
181- def _finalize_handlers (self ):
182- self .handlers = Immutable (self .handlers )
183-
184- def _reset_handlers (self ):
185- self .handlers = dict (self .handlers )
186-
187161 def _compile_regex (self ):
188162 components = []
189163
@@ -225,11 +199,14 @@ def finalize(self):
225199 self ._finalize_params ()
226200 if self .regex :
227201 self ._compile_regex ()
228- self ._finalize_methods ()
229- self ._finalize_handlers ()
202+ self .requirements = Immutable (self .requirements )
230203
231204 def reset (self ):
232- self ._reset_handlers ()
205+ self .requirements = dict (self .requirements )
206+
207+ @property
208+ def defined_params (self ):
209+ return self ._params
233210
234211 @property
235212 def raw_path (self ):
0 commit comments