feat(routing): Allow digits and underscore in compile_uri_template
Allow URI template fields to contain numbers so long as the field name does not start with a numeral. Example: "test123" is valid, while "123test" is not. This patch adds support for this in the legacy template helpers, and also adds an additional test for these chars for the current router spec. Co-Authored-By: Kurt Griffiths <mail@kgriffs.com>
This commit is contained in:
committed by
Kurt Griffiths
parent
e10ff51027
commit
efa763042f
@@ -65,7 +65,9 @@ def compile_uri_template(template):
|
||||
if template != '/' and template.endswith('/'):
|
||||
template = template[:-1]
|
||||
|
||||
expression_pattern = r'{([a-zA-Z][a-zA-Z_]*)}'
|
||||
# template names should be able to start with A-Za-z
|
||||
# but also contain 0-9_ in the remaining portion
|
||||
expression_pattern = r'{([a-zA-Z]\w*)}'
|
||||
|
||||
# Get a list of field names
|
||||
fields = set(re.findall(expression_pattern, template))
|
||||
|
||||
@@ -27,6 +27,18 @@ class NameResource(object):
|
||||
self.called = True
|
||||
|
||||
|
||||
class NameAndDigitResource(object):
|
||||
def __init__(self):
|
||||
self.id = None
|
||||
self.name51 = None
|
||||
self.called = False
|
||||
|
||||
def on_get(self, req, resp, id, name51):
|
||||
self.id = id
|
||||
self.name51 = name51
|
||||
self.called = True
|
||||
|
||||
|
||||
class TestUriTemplates(testing.TestBase):
|
||||
|
||||
def before(self):
|
||||
@@ -116,6 +128,20 @@ class TestUriTemplates(testing.TestBase):
|
||||
self.assertNotIn(kwargs, 'Id')
|
||||
self.assertEqual(req.get_param('id'), None)
|
||||
|
||||
def test_single_with_trailing_digits(self):
|
||||
self.api.add_route('/widgets/{id12}', self.resource)
|
||||
|
||||
self.simulate_request('/widgets/123')
|
||||
self.assertTrue(self.resource.called)
|
||||
self.assertEqual(self.resource.kwargs['id12'], '123')
|
||||
|
||||
def test_single_with_underscore(self):
|
||||
self.api.add_route('/widgets/{widget_id}', self.resource)
|
||||
|
||||
self.simulate_request('/widgets/123')
|
||||
self.assertTrue(self.resource.called)
|
||||
self.assertEqual(self.resource.kwargs['widget_id'], '123')
|
||||
|
||||
def test_single_trailing_slash(self):
|
||||
resource1 = IDResource()
|
||||
self.api.add_route('/1/{id}/', resource1)
|
||||
@@ -158,6 +184,19 @@ class TestUriTemplates(testing.TestBase):
|
||||
self.assertEqual(resource.id, test_id)
|
||||
self.assertEqual(resource.name, test_name)
|
||||
|
||||
def test_multiple_with_digits(self):
|
||||
resource = NameAndDigitResource()
|
||||
self.api.add_route('/messages/{id}/names/{name51}', resource)
|
||||
|
||||
test_id = self.getUniqueString()
|
||||
test_name = self.getUniqueString()
|
||||
path = '/messages/' + test_id + '/names/' + test_name
|
||||
self.simulate_request(path)
|
||||
self.assertTrue(resource.called)
|
||||
|
||||
self.assertEqual(resource.id, test_id)
|
||||
self.assertEqual(resource.name51, test_name)
|
||||
|
||||
def test_empty_path_component(self):
|
||||
self.assertRaises(ValueError, self.api.add_route,
|
||||
'//', self.resource)
|
||||
|
||||
@@ -69,15 +69,30 @@ class TestUriTemplates(testing.TestBase):
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(result.groupdict(), {'name': 'Kelsier'})
|
||||
|
||||
def test_one_field_with_digits(self):
|
||||
fields, pattern = routing.compile_uri_template('/{name123}')
|
||||
self.assertEqual(fields, set(['name123']))
|
||||
|
||||
result = pattern.match('/Kelsier')
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(result.groupdict(), {'name123': 'Kelsier'})
|
||||
|
||||
def test_one_field_with_prefixed_digits(self):
|
||||
fields, pattern = routing.compile_uri_template('/{37signals}')
|
||||
self.assertEqual(fields, set())
|
||||
|
||||
result = pattern.match('/s2n')
|
||||
self.assertFalse(result)
|
||||
|
||||
@ddt.data('', '/')
|
||||
def test_two_fields(self, postfix):
|
||||
path = '/book/{id}/characters/{name}' + postfix
|
||||
path = '/book/{book_id}/characters/{n4m3}' + postfix
|
||||
fields, pattern = routing.compile_uri_template(path)
|
||||
self.assertEqual(fields, set(['name', 'id']))
|
||||
self.assertEqual(fields, set(['n4m3', 'book_id']))
|
||||
|
||||
result = pattern.match('/book/0765350386/characters/Vin')
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(result.groupdict(), {'name': 'Vin', 'id': '0765350386'})
|
||||
self.assertEqual(result.groupdict(), {'n4m3': 'Vin', 'book_id': '0765350386'})
|
||||
|
||||
def test_three_fields(self):
|
||||
fields, pattern = routing.compile_uri_template('/{a}/{b}/x/{c}')
|
||||
|
||||
Reference in New Issue
Block a user