summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pyramid/tests/test_urldispatch.py24
-rw-r--r--pyramid/urldispatch.py23
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