diff options
| -rw-r--r-- | pyramid/tests/test_urldispatch.py | 24 | ||||
| -rw-r--r-- | pyramid/urldispatch.py | 23 |
2 files changed, 42 insertions, 5 deletions
diff --git a/pyramid/tests/test_urldispatch.py b/pyramid/tests/test_urldispatch.py index 856bdcb78..286cc1573 100644 --- a/pyramid/tests/test_urldispatch.py +++ b/pyramid/tests/test_urldispatch.py @@ -365,6 +365,30 @@ class TestCompileRoute(unittest.TestCase): # should be a native string self.assertEqual(type(result), str) + def test_highorder_pattern_utf8(self): + pattern = b'/La Pe\xc3\xb1a/{city}' + self.assertRaises(ValueError, self._callFUT, pattern) + + def test_generate_with_string_remainder_and_unicode_replacement(self): + pattern = text_(b'/abc*remainder', 'utf-8') + _, generator = self._callFUT(pattern) + result = generator( + {'remainder': text_(b'/Qu\xc3\xa9bec/La Pe\xc3\xb1a', 'utf-8')} + ) + self.assertEqual(result, '/abc/Qu%C3%A9bec/La%20Pe%C3%B1a') + # should be a native string + self.assertEqual(type(result), str) + + def test_generate_with_string_remainder_and_nonstring_replacement(self): + pattern = text_(b'/abc/*remainder', 'utf-8') + _, generator = self._callFUT(pattern) + result = generator( + {'remainder': None} + ) + self.assertEqual(result, '/abc/None') + # should be a native string + self.assertEqual(type(result), str) + class TestCompileRouteFunctional(unittest.TestCase): def matches(self, pattern, path, expected): from pyramid.urldispatch import _compile_route diff --git a/pyramid/urldispatch.py b/pyramid/urldispatch.py index cb0e57c4d..fcd6c55c9 100644 --- a/pyramid/urldispatch.py +++ b/pyramid/urldispatch.py @@ -111,7 +111,13 @@ def _compile_route(route): # want to accept bytestrings with high-order characters in them here as # we have no idea what the encoding represents. if route.__class__ is not text_type: - route = text_(route, 'ascii') + try: + route = text_(route, 'ascii') + except UnicodeDecodeError: + raise ValueError( + 'The pattern value passed to add_route must be ' + 'either a Unicode string or a plain string without ' + 'any non-ASCII characters (you provided %r).' % route) if old_route_re.search(route) and not route_re.search(route): route = old_route_re.sub(update_pattern, route) @@ -202,13 +208,20 @@ def _compile_route(route): if v.__class__ is text_type: # url_quote below needs bytes, not unicode on Py2 v = v.encode('utf-8') - if k == remainder and is_nonstr_iter(v): - v = '/'.join([quote_path_segment(x) for x in v]) # native - elif k != remainder: + + if k == remainder: + # a stararg argument + if is_nonstr_iter(v): + v = '/'.join([quote_path_segment(x) for x in v]) # native + else: + if v.__class__ not in string_types: + v = str(v) + v = quote_path_segment(v, safe='/') + else: if v.__class__ not in string_types: v = str(v) # v may be bytes (py2) or native string (py3) - v = url_quote(v, safe='') # defaults to utf8 encoding on py3 + v = quote_path_segment(v) # at this point, the value will be a native string newdict[k] = v |
