diff --git a/sanic/router.py b/sanic/router.py index 0af1d13d..917a6812 100644 --- a/sanic/router.py +++ b/sanic/router.py @@ -2,6 +2,7 @@ import re from collections import defaultdict, namedtuple from collections.abc import Iterable from functools import lru_cache +from types import MappingProxyType from sanic.exceptions import NotFound, InvalidUsage from sanic.views import CompositionView @@ -11,13 +12,13 @@ Route = namedtuple( ['handler', 'methods', 'pattern', 'parameters', 'name', 'uri']) Parameter = namedtuple('Parameter', ['name', 'cast']) -REGEX_TYPES = { +REGEX_TYPES = MappingProxyType({ 'string': (str, r'[^/]+'), 'int': (int, r'\d+'), 'number': (float, r'[0-9\\.]+'), 'alpha': (str, r'[A-Za-z]+'), 'path': (str, r'[^/].*?'), -} +}) ROUTER_CACHE_SIZE = 1024 @@ -65,7 +66,7 @@ class Router: routes_always_check = None parameter_pattern = re.compile(r'<(.+?)>') - def __init__(self, converters=None): + def __init__(self, converters=REGEX_TYPES): self.routes_all = {} self.routes_names = {} self.routes_static_files = {} @@ -73,9 +74,7 @@ class Router: self.routes_dynamic = defaultdict(list) self.routes_always_check = [] self.hosts = set() - self._converters = REGEX_TYPES - if converters: - self._converters.update(converters) + self._converters = dict(converters) def parse_parameter_string(self, parameter_string): """Parse a parameter string into its constituent name, type, and diff --git a/tests/test_routes.py b/tests/test_routes.py index 23c5ca83..aaed2df7 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,11 +1,12 @@ import asyncio -import pytest import uuid +import pytest + from sanic import Sanic -from sanic.response import text -from sanic.router import RouteExists, RouteDoesNotExist, Router from sanic.constants import HTTP_METHODS +from sanic.response import text +from sanic.router import RouteExists, RouteDoesNotExist, Router, REGEX_TYPES # ------------------------------------------------------------ # @@ -886,3 +887,25 @@ def test_custom_route_converters(): assert response.text == 'OK' assert isinstance(results[0], uuid.UUID) + + +def test_extend_default_rules(): + regex = r'[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-' \ + r'[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}' + rules = dict(REGEX_TYPES) + rules.update({ + "uuid": (uuid.UUID, regex) + }) + custom_router = Router(converters=rules) + app = Sanic('test_custom_route_converters', router=custom_router) + results = [] + + @app.route('/') + async def handler(request, id): + results.append(id) + return text('OK') + + request, response = app.test_client.get('/e010dcb8-6b40-11e7-8e04-0242ac120022') + + assert response.text == 'OK' + assert isinstance(results[0], uuid.UUID)