Add simple uri hash to lookup

This commit is contained in:
John Piasetzki 2016-10-20 01:07:16 -04:00
parent f4b45deb7f
commit fc4c192237

View File

@ -1,5 +1,5 @@
import re import re
from collections import namedtuple from collections import defaultdict, namedtuple
from functools import lru_cache from functools import lru_cache
from .config import Config from .config import Config
from .exceptions import NotFound, InvalidUsage from .exceptions import NotFound, InvalidUsage
@ -15,6 +15,10 @@ REGEX_TYPES = {
} }
def url_hash(url):
return '/'.join(':' for s in url.split('/'))
class Router: class Router:
""" """
Router supports basic routing with parameters and method checks Router supports basic routing with parameters and method checks
@ -36,7 +40,7 @@ class Router:
routes = None routes = None
def __init__(self): def __init__(self):
self.routes = [] self.routes = defaultdict(list)
def add(self, uri, methods, handler): def add(self, uri, methods, handler):
""" """
@ -74,7 +78,10 @@ class Router:
route = Route( route = Route(
handler=handler, methods=methods, pattern=pattern, handler=handler, methods=methods, pattern=pattern,
parameters=parameters) parameters=parameters)
self.routes.append(route)
if parameters:
uri = url_hash(uri)
self.routes[uri].append(route)
@lru_cache(maxsize=Config.ROUTER_CACHE_SIZE) @lru_cache(maxsize=Config.ROUTER_CACHE_SIZE)
def get(self, request): def get(self, request):
@ -85,17 +92,22 @@ class Router:
:return: handler, arguments, keyword arguments :return: handler, arguments, keyword arguments
""" """
route = None route = None
for route in self.routes: url = request.url
match = route.pattern.match(request.url) if url in self.routes:
if match: route = self.routes[url][0]
break match = route.pattern.match(url)
else: else:
raise NotFound('Requested URL {} not found'.format(request.url)) for route in self.routes[url_hash(url)]:
match = route.pattern.match(url)
if match:
break
else:
raise NotFound('Requested URL {} not found'.format(url))
if route.methods and request.method not in route.methods: if route.methods and request.method not in route.methods:
raise InvalidUsage( raise InvalidUsage(
'Method {} not allowed for URL {}'.format( 'Method {} not allowed for URL {}'.format(
request.method, request.url), status_code=405) request.method, url), status_code=405)
kwargs = {p.name: p.cast(value) for value, p in zip(match.groups(1), route.parameters)} kwargs = {p.name: p.cast(value) for value, p in zip(match.groups(1), route.parameters)}
return route.handler, [], kwargs return route.handler, [], kwargs