summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-09-24 03:56:29 -0400
committerChris McDonough <chrism@plope.com>2011-09-24 03:56:29 -0400
commita84e17d716774ac1bab5f6a0edf422e21eef96c9 (patch)
treea966fbd443c3e57ea6c153f76c6748893930f5a7
parent2e409a88b60be27f8868c95f0fff806fb6cdc155 (diff)
downloadpyramid-a84e17d716774ac1bab5f6a0edf422e21eef96c9.tar.gz
pyramid-a84e17d716774ac1bab5f6a0edf422e21eef96c9.tar.bz2
pyramid-a84e17d716774ac1bab5f6a0edf422e21eef96c9.zip
slog
-rw-r--r--pyramid/compat.py4
-rw-r--r--pyramid/encode.py84
-rw-r--r--pyramid/testing.py35
-rw-r--r--pyramid/tests/test_config/test_views.py13
-rw-r--r--pyramid/tests/test_encode.py39
-rw-r--r--pyramid/tests/test_httpexceptions.py2
-rw-r--r--pyramid/tests/test_paster.py7
-rw-r--r--pyramid/tests/test_scaffolds.py2
-rw-r--r--pyramid/tests/test_traversal.py21
-rw-r--r--pyramid/tests/test_url.py24
-rw-r--r--pyramid/urldispatch.py4
11 files changed, 100 insertions, 135 deletions
diff --git a/pyramid/compat.py b/pyramid/compat.py
index d83205c87..ecb661ce9 100644
--- a/pyramid/compat.py
+++ b/pyramid/compat.py
@@ -64,13 +64,15 @@ try: # pragma: no cover
from urllib import parse
urlparse = parse
from urllib.parse import quote as url_quote
+ from urllib.parse import quote_plus as url_quote_plus
from urllib.parse import unquote as url_unquote
- url_unquote_text = url_unquote
from urllib.parse import urlencode as url_encode
from urllib.request import urlopen as url_open
+ url_unquote_text = url_unquote
except ImportError:
import urlparse
from urllib import quote as url_quote
+ from urllib import quote_plus as url_quote_plus
from urllib import unquote as url_unquote
from urllib import urlencode as url_encode
from urllib2 import urlopen as url_open
diff --git a/pyramid/encode.py b/pyramid/encode.py
index ee574a0eb..a259d1414 100644
--- a/pyramid/encode.py
+++ b/pyramid/encode.py
@@ -1,62 +1,11 @@
-import re
-
from pyramid.compat import text_type
-from pyramid.compat import native_
+from pyramid.compat import binary_type
from pyramid.compat import is_nonstr_iter
+from pyramid.compat import url_quote as _url_quote
+from pyramid.compat import url_quote_plus as quote_plus # bw compat api (dnr)
-always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
- 'abcdefghijklmnopqrstuvwxyz'
- '0123456789' '_.-')
-_safemaps = {}
-_must_quote = {}
-
-def url_quote(s, safe=''):
- """quote('abc def') -> 'abc%20def'
-
- Each part of a URL, e.g. the path info, the query, etc., has a
- different set of reserved characters that must be quoted.
-
- RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists
- the following reserved characters::
-
- reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
- "$" | ","
-
- Each of these characters is reserved in some component of a URL,
- but not necessarily in all of them.
-
- Unlike the default version of this function in the Python stdlib, by
- default, the url_quote function is intended for quoting individual path
- segments instead of an already composed path that might have ``/``
- characters in it. Thus, it *will* encode any ``/`` character it finds in a
- string unless ``/`` is marked as 'safe'. It is also slightly faster than
- the stdlib version.
- """
- cachekey = (safe, always_safe)
- try:
- safe_map = _safemaps[cachekey]
- if not _must_quote[cachekey].search(s):
- return s
- except KeyError:
- safe += always_safe
- _must_quote[cachekey] = re.compile(r'[^%s]' % safe)
- safe_map = {}
- for i in range(256):
- c = chr(i)
- if c in safe:
- safe_map[c] = c
- else:
- safe_map[c] = '%%%02X' % i
- _safemaps[cachekey] = safe_map
- res = map(safe_map.__getitem__, s)
- return ''.join(res)
-
-def quote_plus(s, safe=''):
- """ Version of stdlib quote_plus which uses faster url_quote """
- if ' ' in s:
- s = url_quote(s, safe + ' ')
- return s.replace(' ', '+')
- return url_quote(s, safe)
+def url_quote(s, safe=''): # bw compat api
+ return _url_quote(s, safe=safe)
def urlencode(query, doseq=True):
"""
@@ -92,21 +41,26 @@ def urlencode(query, doseq=True):
prefix = ''
for (k, v) in query:
- if k.__class__ is text_type:
- k = native_(k, 'utf-8')
- k = quote_plus(str(k))
+ k = _enc(k)
+
if is_nonstr_iter(v):
for x in v:
- if x.__class__ is text_type:
- x = native_(x, 'utf-8')
- x = quote_plus(str(x))
+ x = _enc(x)
result += '%s%s=%s' % (prefix, k, x)
prefix = '&'
else:
- if v.__class__ is text_type:
- v = native_(v, 'utf-8')
- v = quote_plus(str(v))
+ v = _enc(v)
result += '%s%s=%s' % (prefix, k, v)
+
prefix = '&'
return result
+
+def _enc(val):
+ cls = val.__class__
+ if cls is text_type:
+ val = val.encode('utf-8')
+ elif cls is not binary_type:
+ val = str(val).encode('utf-8')
+ return quote_plus(val)
+
diff --git a/pyramid/testing.py b/pyramid/testing.py
index 862d31459..89cd39a1b 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -14,6 +14,9 @@ from pyramid.interfaces import IView
from pyramid.interfaces import IViewClassifier
from pyramid.interfaces import ISession
+from pyramid.compat import PY3
+from pyramid.compat import PYPY
+from pyramid.compat import class_types
from pyramid.config import Configurator
from pyramid.decorator import reify
from pyramid.httpexceptions import HTTPForbidden
@@ -896,21 +899,25 @@ class MockTemplate(object):
return self.response
def skip_on(*platforms):
+ skip = False
+ for platform in platforms:
+ if skip_on.os_name.startswith(platform):
+ skip = True
+ if platform == 'pypy' and PYPY: # pragma: no cover
+ skip = True
+ if platform == 'py3' and PY3: # pragma: no cover
+ skip = True
def decorator(func):
- def wrapper(*args, **kw):
- for platform in platforms:
- if skip_on.os_name.startswith(platform):
- return
- if platform == 'pypy' and skip_on.pypy: # pragma: no cover
+ if isinstance(func, class_types):
+ if skip: return None
+ else: return func
+ else:
+ def wrapper(*args, **kw):
+ if skip:
return
- return func(*args, **kw)
- wrapper.__name__ = func.__name__
- wrapper.__doc__ = func.__doc__
- return wrapper
+ return func(*args, **kw)
+ wrapper.__name__ = func.__name__
+ wrapper.__doc__ = func.__doc__
+ return wrapper
return decorator
skip_on.os_name = os.name # for testing
-try: # pragma: no cover
- import __pypy__
- skip_on.pypy = True
-except ImportError:
- skip_on.pypy = False
diff --git a/pyramid/tests/test_config/test_views.py b/pyramid/tests/test_config/test_views.py
index 141b60e87..9f2ff9b6f 100644
--- a/pyramid/tests/test_config/test_views.py
+++ b/pyramid/tests/test_config/test_views.py
@@ -5,6 +5,7 @@ from pyramid.tests.test_config import IDummy
from pyramid.tests.test_config import dummy_view
+from pyramid.compat import im_func
from pyramid.exceptions import ConfigurationError
from pyramid.exceptions import ConfigurationExecutionError
from pyramid.exceptions import ConfigurationConflictError
@@ -3245,12 +3246,12 @@ class Test_preserve_view_attrs(unittest.TestCase):
self.assertTrue(view1.__doc__ is view2.__doc__)
self.assertTrue(view1.__module__ is view2.__module__)
self.assertTrue(view1.__name__ is view2.__name__)
- self.assertTrue(view1.__call_permissive__.im_func is
- view2.__call_permissive__.im_func)
- self.assertTrue(view1.__permitted__.im_func is
- view2.__permitted__.im_func)
- self.assertTrue(view1.__predicated__.im_func is
- view2.__predicated__.im_func)
+ self.assertTrue(getattr(view1.__call_permissive__, im_func) is
+ getattr(view2.__call_permissive__, im_func))
+ self.assertTrue(getattr(view1.__permitted__, im_func) is
+ getattr(view2.__permitted__, im_func))
+ self.assertTrue(getattr(view1.__predicated__, im_func) is
+ getattr(view2.__predicated__, im_func))
class TestStaticURLInfo(unittest.TestCase):
diff --git a/pyramid/tests/test_encode.py b/pyramid/tests/test_encode.py
index 738efeea2..ccc8f16e3 100644
--- a/pyramid/tests/test_encode.py
+++ b/pyramid/tests/test_encode.py
@@ -1,5 +1,6 @@
import unittest
from pyramid.compat import text_
+from pyramid.compat import native_
class UrlEncodeTests(unittest.TestCase):
def _callFUT(self, query, doseq=False):
@@ -11,17 +12,17 @@ class UrlEncodeTests(unittest.TestCase):
self.assertEqual(result, 'a=1&b=2')
def test_unicode_key(self):
- la = text_('LaPe\xc3\xb1a', 'utf-8')
+ la = text_(b'LaPe\xc3\xb1a', 'utf-8')
result = self._callFUT([(la, 1), ('b',2)])
self.assertEqual(result, 'LaPe%C3%B1a=1&b=2')
def test_unicode_val_single(self):
- la = text_('LaPe\xc3\xb1a', 'utf-8')
+ la = text_(b'LaPe\xc3\xb1a', 'utf-8')
result = self._callFUT([('a', la), ('b',2)])
self.assertEqual(result, 'a=LaPe%C3%B1a&b=2')
def test_unicode_val_multiple(self):
- la = [text_('LaPe\xc3\xb1a', 'utf-8')] * 2
+ la = [text_(b'LaPe\xc3\xb1a', 'utf-8')] * 2
result = self._callFUT([('a', la), ('b',2)], doseq=True)
self.assertEqual(result, 'a=LaPe%C3%B1a&a=LaPe%C3%B1a&b=2')
@@ -30,6 +31,10 @@ class UrlEncodeTests(unittest.TestCase):
result = self._callFUT([('a', s)], doseq=True)
self.assertEqual(result, 'a=1&a=2')
+ def test_with_spaces(self):
+ result = self._callFUT([('a', '123 456')], doseq=True)
+ self.assertEqual(result, 'a=123+456')
+
def test_dict(self):
result = self._callFUT({'a':1})
self.assertEqual(result, 'a=1')
@@ -39,29 +44,17 @@ class URLQuoteTests(unittest.TestCase):
from pyramid.encode import url_quote
return url_quote(val, safe)
- def test_it_default(self):
- la = 'La/Pe\xc3\xb1a'
+ def test_it_bytes(self):
+ la = b'La/Pe\xc3\xb1a'
result = self._callFUT(la)
self.assertEqual(result, 'La%2FPe%C3%B1a')
- def test_it_with_safe(self):
- la = 'La/Pe\xc3\xb1a'
- result = self._callFUT(la, '/')
- self.assertEqual(result, 'La/Pe%C3%B1a')
-
-class TestQuotePlus(unittest.TestCase):
- def _callFUT(self, val, safe=''):
- from pyramid.encode import quote_plus
- return quote_plus(val, safe)
-
- def test_it_default(self):
- la = 'La Pe\xc3\xb1a'
+ def test_it_native(self):
+ la = native_(b'La/Pe\xc3\xb1a', 'utf-8')
result = self._callFUT(la)
- self.assertEqual(result, 'La+Pe%C3%B1a')
-
+ self.assertEqual(result, 'La%2FPe%C3%B1a')
+
def test_it_with_safe(self):
- la = 'La /Pe\xc3\xb1a'
+ la = b'La/Pe\xc3\xb1a'
result = self._callFUT(la, '/')
- self.assertEqual(result, 'La+/Pe%C3%B1a')
-
-
+ self.assertEqual(result, 'La/Pe%C3%B1a')
diff --git a/pyramid/tests/test_httpexceptions.py b/pyramid/tests/test_httpexceptions.py
index 6bc7fbb30..927d27733 100644
--- a/pyramid/tests/test_httpexceptions.py
+++ b/pyramid/tests/test_httpexceptions.py
@@ -277,7 +277,7 @@ class TestRenderAllExceptionsWithoutArguments(unittest.TestCase):
exc.content_type = content_type
result = list(exc(environ, start_response))[0]
if exc.empty_body:
- self.assertEqual(result, '')
+ self.assertEqual(result, b'')
else:
self.assertTrue(bytes_(exc.status) in result)
L.append(result)
diff --git a/pyramid/tests/test_paster.py b/pyramid/tests/test_paster.py
index f46aca49d..a697b5691 100644
--- a/pyramid/tests/test_paster.py
+++ b/pyramid/tests/test_paster.py
@@ -1,5 +1,7 @@
import unittest
+from pyramid.testing import skip_on
+@skip_on('py3')
class TestPShellCommand(unittest.TestCase):
def _getTargetClass(self):
from pyramid.paster import PShellCommand
@@ -246,6 +248,7 @@ class TestPShellCommand(unittest.TestCase):
self.assertTrue(self.bootstrap.closer.called)
self.assertTrue(shell.help)
+@skip_on('py3')
class TestPRoutesCommand(unittest.TestCase):
def _getTargetClass(self):
from pyramid.paster import PRoutesCommand
@@ -372,6 +375,7 @@ class TestPRoutesCommand(unittest.TestCase):
result = command._get_mapper(registry)
self.assertEqual(result.__class__, RoutesMapper)
+@skip_on('py3')
class TestPViewsCommand(unittest.TestCase):
def _getTargetClass(self):
from pyramid.paster import PViewsCommand
@@ -824,6 +828,7 @@ class TestPViewsCommand(unittest.TestCase):
self.assertEqual(L[8], ' pyramid.tests.test_paster.view.call')
self.assertEqual(L[9], ' view predicates (predicate = x)')
+@skip_on('py3')
class TestGetApp(unittest.TestCase):
def _callFUT(self, config_file, section_name, loadapp):
from pyramid.paster import get_app
@@ -859,6 +864,7 @@ class TestGetApp(unittest.TestCase):
self.assertEqual(loadapp.relative_to, os.getcwd())
self.assertEqual(result, app)
+@skip_on('py3')
class TestBootstrap(unittest.TestCase):
def _callFUT(self, config_uri, request=None):
from pyramid.paster import bootstrap
@@ -898,6 +904,7 @@ class TestBootstrap(unittest.TestCase):
self.assertEqual(result['root'], self.root)
self.assert_('closer' in result)
+@skip_on('py3')
class TestPTweensCommand(unittest.TestCase):
def _getTargetClass(self):
from pyramid.paster import PTweensCommand
diff --git a/pyramid/tests/test_scaffolds.py b/pyramid/tests/test_scaffolds.py
index ed2c5a993..265e20c3b 100644
--- a/pyramid/tests/test_scaffolds.py
+++ b/pyramid/tests/test_scaffolds.py
@@ -1,5 +1,7 @@
import unittest
+from pyramid.testing import skip_on
+@skip_on('py3')
class TestPyramidTemplate(unittest.TestCase):
def _getTargetClass(self):
from pyramid.scaffolds import PyramidTemplate
diff --git a/pyramid/tests/test_traversal.py b/pyramid/tests/test_traversal.py
index cd48d0268..07f7515eb 100644
--- a/pyramid/tests/test_traversal.py
+++ b/pyramid/tests/test_traversal.py
@@ -4,6 +4,7 @@ from pyramid.testing import cleanUp
from pyramid.compat import text_
from pyramid.compat import native_
from pyramid.compat import text_type
+from pyramid.compat import url_quote
class TraversalPathTests(unittest.TestCase):
def _callFUT(self, path):
@@ -42,18 +43,16 @@ class TraversalPathTests(unittest.TestCase):
self.assertEqual(result2, (text_('foo'), text_('bar')))
def test_utf8(self):
- import urllib
- la = 'La Pe\xc3\xb1a'
- encoded = urllib.quote(la)
+ la = b'La Pe\xc3\xb1a'
+ encoded = url_quote(la)
decoded = text_(la, 'utf-8')
path = '/'.join([encoded, encoded])
self.assertEqual(self._callFUT(path), (decoded, decoded))
def test_utf16(self):
from pyramid.exceptions import URLDecodeError
- import urllib
- la = text_('La Pe\xc3\xb1a', 'utf-8').encode('utf-16')
- encoded = urllib.quote(la)
+ la = text_(b'La Pe\xc3\xb1a', 'utf-8').encode('utf-16')
+ encoded = url_quote(la)
path = '/'.join([encoded, encoded])
self.assertRaises(URLDecodeError, self._callFUT, path)
@@ -67,7 +66,7 @@ class TraversalPathTests(unittest.TestCase):
self.assertEqual(self._callFUT(path), (text_('abc'),))
def test_unicode_undecodeable_to_ascii(self):
- path = text_('/La Pe\xc3\xb1a', 'utf-8')
+ path = text_(b'/La Pe\xc3\xb1a', 'utf-8')
self.assertRaises(UnicodeEncodeError, self._callFUT, path)
class ResourceTreeTraverserTests(unittest.TestCase):
@@ -604,7 +603,7 @@ class FindResourceTests(unittest.TestCase):
root = DummyContext(unprintable)
unprintable.__parent__ = root
unprintable.__name__ = text_(
- '/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', 'utf-8')
+ b'/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', 'utf-8')
root.__parent__ = None
root.__name__ = None
traverser = ResourceTreeTraverser
@@ -757,7 +756,7 @@ class QuotePathSegmentTests(unittest.TestCase):
return quote_path_segment(s)
def test_unicode(self):
- la = text_('/La Pe\xc3\xb1a', 'utf-8')
+ la = text_(b'/La Pe\xc3\xb1a', 'utf-8')
result = self._callFUT(la)
self.assertEqual(result, '%2FLa%20Pe%C3%B1a')
@@ -774,7 +773,7 @@ class QuotePathSegmentTests(unittest.TestCase):
def test_long(self):
from pyramid.compat import long
import sys
- s = long(sys.maxint + 1)
+ s = long(sys.maxsize + 1)
result = self._callFUT(s)
expected = str(s)
self.assertEqual(result, expected)
@@ -847,7 +846,7 @@ class TraversalContextURLTests(unittest.TestCase):
root.__name__ = None
one = DummyContext()
one.__parent__ = root
- one.__name__ = text_('La Pe\xc3\xb1a', 'utf-8')
+ one.__name__ = text_(b'La Pe\xc3\xb1a', 'utf-8')
two = DummyContext()
two.__parent__ = one
two.__name__ = 'La Pe\xc3\xb1a'
diff --git a/pyramid/tests/test_url.py b/pyramid/tests/test_url.py
index 22eacd758..aa6fa30dd 100644
--- a/pyramid/tests/test_url.py
+++ b/pyramid/tests/test_url.py
@@ -49,7 +49,7 @@ class TestURLMethodsMixin(unittest.TestCase):
def test_resource_url_unicode_in_element_names(self):
request = self._makeOne()
self._registerContextURL(request.registry)
- uc = text_('La Pe\xc3\xb1a', 'utf-8')
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
context = DummyContext()
result = request.resource_url(context, uc)
self.assertEqual(result,
@@ -74,7 +74,7 @@ class TestURLMethodsMixin(unittest.TestCase):
request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- uc = text_('La Pe\xc3\xb1a', 'utf-8')
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
result = request.resource_url(context, 'a', query={'a':uc})
self.assertEqual(result,
'http://example.com/context/a?a=La+Pe%C3%B1a')
@@ -83,9 +83,9 @@ class TestURLMethodsMixin(unittest.TestCase):
request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- uc = text_('La Pe\xc3\xb1a', 'utf-8')
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
result = request.resource_url(context, 'a', query=[('a', 'hi there'),
- ('b', uc)])
+ ('b', uc)])
self.assertEqual(result,
'http://example.com/context/a?a=hi+there&b=La+Pe%C3%B1a')
@@ -118,7 +118,7 @@ class TestURLMethodsMixin(unittest.TestCase):
request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- uc = text_('La Pe\xc3\xb1a', 'utf-8')
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
result = request.resource_url(context, anchor=uc)
self.assertEqual(result,
'http://example.com/context/#La Pe\xc3\xb1a')
@@ -173,7 +173,7 @@ class TestURLMethodsMixin(unittest.TestCase):
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
result = request.route_url('flub', a=1, b=2, c=3, _query={'a':1},
- _anchor=text_("foo"))
+ _anchor=text_(b"foo"))
self.assertEqual(result,
'http://example.com:5432/1/2/3?a=1#foo')
@@ -191,7 +191,7 @@ class TestURLMethodsMixin(unittest.TestCase):
request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- anchor = text_('La Pe\xc3\xb1a', 'utf-8')
+ anchor = text_(b'La Pe\xc3\xb1a', 'utf-8')
result = request.route_url('flub', _anchor=anchor)
self.assertEqual(result,
'http://example.com:5432/1/2/3#La Pe\xc3\xb1a')
@@ -282,7 +282,7 @@ class TestURLMethodsMixin(unittest.TestCase):
request.matchdict = {}
request.registry.registerUtility(mapper, IRoutesMapper)
result = request.current_route_url('extra1', 'extra2', _query={'a':1},
- _anchor=text_("foo"))
+ _anchor=text_(b"foo"))
self.assertEqual(result,
'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo')
@@ -295,7 +295,7 @@ class TestURLMethodsMixin(unittest.TestCase):
request.matchdict = {}
request.registry.registerUtility(mapper, IRoutesMapper)
result = request.current_route_url('extra1', 'extra2', _query={'a':1},
- _anchor=text_("foo"),
+ _anchor=text_(b"foo"),
_route_name='bar')
self.assertEqual(result,
'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo')
@@ -310,7 +310,7 @@ class TestURLMethodsMixin(unittest.TestCase):
request.script_name = '/script_name'
request.registry.registerUtility(mapper, IRoutesMapper)
result = request.current_route_path('extra1', 'extra2', _query={'a':1},
- _anchor=text_("foo"))
+ _anchor=text_(b"foo"))
self.assertEqual(result, '/script_name/1/2/3/extra1/extra2?a=1#foo')
def test_route_path_with_elements(self):
@@ -321,7 +321,7 @@ class TestURLMethodsMixin(unittest.TestCase):
request.script_name = ''
result = request.route_path('flub', 'extra1', 'extra2',
a=1, b=2, c=3, _query={'a':1},
- _anchor=text_("foo"))
+ _anchor=text_(b"foo"))
self.assertEqual(result, '/1/2/3/extra1/extra2?a=1#foo')
def test_route_path_with_script_name(self):
@@ -332,7 +332,7 @@ class TestURLMethodsMixin(unittest.TestCase):
request.registry.registerUtility(mapper, IRoutesMapper)
result = request.route_path('flub', 'extra1', 'extra2',
a=1, b=2, c=3, _query={'a':1},
- _anchor=text_("foo"))
+ _anchor=text_(b"foo"))
self.assertEqual(result, '/foo/1/2/3/extra1/extra2?a=1#foo')
def test_static_url_staticurlinfo_notfound(self):
diff --git a/pyramid/urldispatch.py b/pyramid/urldispatch.py
index 696b69f89..b11bcefcb 100644
--- a/pyramid/urldispatch.py
+++ b/pyramid/urldispatch.py
@@ -8,7 +8,7 @@ from pyramid.compat import url_unquote_text
from pyramid.compat import native_
from pyramid.compat import text_type
from pyramid.compat import is_nonstr_iter
-from pyramid.encode import url_quote
+from pyramid.compat import url_quote
from pyramid.exceptions import URLDecodeError
from pyramid.traversal import traversal_path
from pyramid.traversal import quote_path_segment
@@ -163,7 +163,7 @@ def _compile_route(route):
v = '/'.join([quote_path_segment(x) for x in v])
elif k != star:
try:
- v = url_quote(v)
+ v = url_quote(v, safe='')
except TypeError:
pass
newdict[k] = v