summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-09-24 08:32:16 -0400
committerChris McDonough <chrism@plope.com>2011-09-24 08:32:16 -0400
commit5942ec4b3e9211436f2ccf044f3cf03a4a9960b2 (patch)
treee46049414cf8d199f17f2488ecd1c8d8542f6120
parentfccffe9c468ec652e07c13991cb340e76e82166d (diff)
downloadpyramid-5942ec4b3e9211436f2ccf044f3cf03a4a9960b2.tar.gz
pyramid-5942ec4b3e9211436f2ccf044f3cf03a4a9960b2.tar.bz2
pyramid-5942ec4b3e9211436f2ccf044f3cf03a4a9960b2.zip
more wtfing
-rw-r--r--pyramid/tests/test_traversal.py12
-rw-r--r--pyramid/traversal.py116
2 files changed, 81 insertions, 47 deletions
diff --git a/pyramid/tests/test_traversal.py b/pyramid/tests/test_traversal.py
index 07f7515eb..9af47aec3 100644
--- a/pyramid/tests/test_traversal.py
+++ b/pyramid/tests/test_traversal.py
@@ -608,9 +608,12 @@ class FindResourceTests(unittest.TestCase):
root.__name__ = None
traverser = ResourceTreeTraverser
self._registerTraverser(traverser)
+ # fails on py3
+ # path_info is /<chinesechars> on py3, likely not so much on py2
result = self._callFUT(
root,
- text_('/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF'))
+ text_(b'/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF')
+ )
self.assertEqual(result, unprintable)
class ResourcePathTests(unittest.TestCase):
@@ -849,12 +852,13 @@ class TraversalContextURLTests(unittest.TestCase):
one.__name__ = text_(b'La Pe\xc3\xb1a', 'utf-8')
two = DummyContext()
two.__parent__ = one
- two.__name__ = 'La Pe\xc3\xb1a'
+ two.__name__ = b'La Pe\xc3\xb1a'
request = DummyRequest()
context_url = self._makeOne(two, request)
result = context_url()
- self.assertEqual(result,
- 'http://example.com:5432/La%20Pe%C3%B1a/La%20Pe%C3%B1a/')
+ self.assertEqual(
+ result,
+ 'http://example.com:5432/La%20Pe%C3%B1a/La%20Pe%C3%B1a/')
def test_call_with_virtual_root_path(self):
from pyramid.interfaces import VH_ROOT_KEY
diff --git a/pyramid/traversal.py b/pyramid/traversal.py
index e535da657..366bee563 100644
--- a/pyramid/traversal.py
+++ b/pyramid/traversal.py
@@ -10,9 +10,11 @@ from pyramid.interfaces import IRequestFactory
from pyramid.interfaces import ITraverser
from pyramid.interfaces import VH_ROOT_KEY
+from pyramid.compat import PY3
from pyramid.compat import native_
from pyramid.compat import text_
from pyramid.compat import text_type
+from pyramid.compat import binary_type
from pyramid.compat import url_unquote_text
from pyramid.compat import is_nonstr_iter
from pyramid.encode import url_quote
@@ -476,8 +478,9 @@ def traversal_path(path):
their own traversal machinery, as opposed to users
writing applications in :app:`Pyramid`.
"""
- if isinstance(path, text_type):
- path = native_(path.encode('ascii'))
+ if (not PY3) and (isinstance(path, text_type)):
+ # XXX this stinks
+ path = path.encode('ascii')
path = path.strip('/')
clean = []
for segment in path.split('/'):
@@ -496,47 +499,74 @@ def traversal_path(path):
_segment_cache = {}
-def quote_path_segment(segment, safe=''):
- """ Return a quoted representation of a 'path segment' (such as
- the string ``__name__`` attribute of a resource) as a string. If the
- ``segment`` passed in is a unicode object, it is converted to a
- UTF-8 string, then it is URL-quoted using Python's
- ``urllib.quote``. If the ``segment`` passed in is a string, it is
- URL-quoted using Python's :mod:`urllib.quote`. If the segment
- passed in is not a string or unicode object, an error will be
- raised. The return value of ``quote_path_segment`` is always a
- string, never Unicode.
-
- You may pass a string of characters that need not be encoded as
- the ``safe`` argument to this function. This corresponds to the
- ``safe`` argument to :mod:`urllib.quote`.
-
- .. note:: The return value for each segment passed to this
- function is cached in a module-scope dictionary for
- speed: the cached version is returned when possible
- rather than recomputing the quoted version. No cache
- emptying is ever done for the lifetime of an
- application, however. If you pass arbitrary
- user-supplied strings to this function (as opposed to
- some bounded set of values from a 'working set' known to
- your application), it may become a memory leak.
- """
- # The bit of this code that deals with ``_segment_cache`` is an
- # optimization: we cache all the computation of URL path segments
- # in this module-scope dictionary with the original string (or
- # unicode value) as the key, so we can look it up later without
- # needing to reencode or re-url-quote it
- try:
- return _segment_cache[(segment, safe)]
- except KeyError:
- ## if segment.__class__ is text_type: # isinstance slighly slower (~15%)
- ## result = url_quote(segment.encode('utf-8'), safe)
- ## else:
- result = url_quote(native_(segment, 'utf-8'), safe)
- # we don't need a lock to mutate _segment_cache, as the below
- # will generate exactly one Python bytecode (STORE_SUBSCR)
- _segment_cache[(segment, safe)] = result
- return result
+quote_path_segment_doc = """ \
+Return a quoted representation of a 'path segment' (such as
+the string ``__name__`` attribute of a resource) as a string. If the
+``segment`` passed in is a unicode object, it is converted to a
+UTF-8 string, then it is URL-quoted using Python's
+``urllib.quote``. If the ``segment`` passed in is a string, it is
+URL-quoted using Python's :mod:`urllib.quote`. If the segment
+passed in is not a string or unicode object, an error will be
+raised. The return value of ``quote_path_segment`` is always a
+string, never Unicode.
+
+You may pass a string of characters that need not be encoded as
+the ``safe`` argument to this function. This corresponds to the
+``safe`` argument to :mod:`urllib.quote`.
+
+.. note::
+
+ The return value for each segment passed to this
+ function is cached in a module-scope dictionary for
+ speed: the cached version is returned when possible
+ rather than recomputing the quoted version. No cache
+ emptying is ever done for the lifetime of an
+ application, however. If you pass arbitrary
+ user-supplied strings to this function (as opposed to
+ some bounded set of values from a 'working set' known to
+ your application), it may become a memory leak.
+"""
+
+
+if PY3: # pragma: no cover
+ # special-case on Python 2 for speed? unchecked
+ def quote_path_segment(segment, safe=''):
+ """ %s """ % quote_path_segment_doc
+ # The bit of this code that deals with ``_segment_cache`` is an
+ # optimization: we cache all the computation of URL path segments
+ # in this module-scope dictionary with the original string (or
+ # unicode value) as the key, so we can look it up later without
+ # needing to reencode or re-url-quote it
+ try:
+ return _segment_cache[(segment, safe)]
+ except KeyError:
+ if segment.__class__ not in (text_type, binary_type):
+ segment = str(segment)
+ result = url_quote(native_(segment, 'utf-8'), safe)
+ # we don't need a lock to mutate _segment_cache, as the below
+ # will generate exactly one Python bytecode (STORE_SUBSCR)
+ _segment_cache[(segment, safe)] = result
+ return result
+else:
+ def quote_path_segment(segment, safe=''):
+ """ %s """ % quote_path_segment_doc
+ # The bit of this code that deals with ``_segment_cache`` is an
+ # optimization: we cache all the computation of URL path segments
+ # in this module-scope dictionary with the original string (or
+ # unicode value) as the key, so we can look it up later without
+ # needing to reencode or re-url-quote it
+ try:
+ return _segment_cache[(segment, safe)]
+ except KeyError:
+ if segment.__class__ is text_type: #isinstance slighly slower (~15%)
+ result = url_quote(segment.encode('utf-8'), safe)
+ else:
+ result = url_quote(str(segment), safe)
+ # we don't need a lock to mutate _segment_cache, as the below
+ # will generate exactly one Python bytecode (STORE_SUBSCR)
+ _segment_cache[(segment, safe)] = result
+ return result
+
@implementer(ITraverser)
class ResourceTreeTraverser(object):