diff options
| -rw-r--r-- | CHANGES.txt | 29 | ||||
| -rw-r--r-- | pyramid/request.py | 9 | ||||
| -rw-r--r-- | pyramid/tests/test_request.py | 12 | ||||
| -rw-r--r-- | pyramid/tests/test_traversal.py | 30 | ||||
| -rw-r--r-- | pyramid/traversal.py | 14 | ||||
| -rw-r--r-- | setup.py | 2 |
6 files changed, 52 insertions, 44 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index bb726738c..41e716065 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -151,3 +151,32 @@ Deprecations featureful ``pyramid.config.Configurator.set_request_method`` should be used in its place (it has all of the same capabilities but can also extend the request object with methods). + +Backwards Incompatibilities +--------------------------- + +- The Pyramid router no longer adds the values ``bfg.routes.route`` and + ``bfg.routes.matchdict`` to the request's WSGI environment dictionary. + These values were docs-deprecated in ``repoze.bfg`` 1.0 (effectively seven + minor releases ago). If your code depended on these values, use + request.matched_route and request.matchdict instead. + +- It is no longer possible to pass an environ dictionary directly to + ``pyramid.traversal.ResourceTreeTraverser.__call__`` (aka + ``ModelGraphTraverser.__call__``). Instead, you must pass a request + object. Passing an environment instead of a request has generated a + deprecation warning since Pyramid 1.1. + +- Pyramid will no longer work properly if you use the + ``webob.request.LegacyRequest`` as a request factory. Instances of the + LegacyRequest class have a ``request.path_info`` which return a string. + This Pyramid release assumes that ``request.path_info`` will + unconditionally be Unicode. + +Dependencies +------------ + +- Pyramid now requires WebOb 1.2b3+ (the prior Pyramid release only relied on + 1.2dev+). This is to ensure that we obtain a version of WebOb that returns + ``request.path_info`` as text. + diff --git a/pyramid/request.py b/pyramid/request.py index 37fac6a46..af3310829 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -454,13 +454,4 @@ def call_app_with_subpath_as_path_info(request, app): new_request.environ['SCRIPT_NAME'] = new_script_name new_request.environ['PATH_INFO'] = new_path_info - # In case downstream WSGI app is a Pyramid app, hack around existence of - # these envars until we can safely remove them (see router.py); in any - # case, even if these get removed, it might be better to not copy the - # existing environ but to create a new one instead. - if 'bfg.routes.route' in new_request.environ: - del new_request.environ['bfg.routes.route'] - if 'bfg.routes.matchdict' in new_request.environ: - del new_request.environ['bfg.routes.matchdict'] - return new_request.get_response(app) diff --git a/pyramid/tests/test_request.py b/pyramid/tests/test_request.py index a95d614f9..86cfd8b09 100644 --- a/pyramid/tests/test_request.py +++ b/pyramid/tests/test_request.py @@ -549,18 +549,6 @@ class Test_call_app_with_subpath_as_path_info(unittest.TestCase): self.assertEqual(request.environ['SCRIPT_NAME'], '/' + encoded) self.assertEqual(request.environ['PATH_INFO'], '/' + encoded) - def test_it_removes_bfg_routes_info(self): - request = DummyRequest({}) - request.environ['bfg.routes.route'] = True - request.environ['bfg.routes.matchdict'] = True - response = self._callFUT(request, 'app') - self.assertTrue(request.copied) - self.assertEqual(response, 'app') - self.assertEqual(request.environ['SCRIPT_NAME'], '') - self.assertEqual(request.environ['PATH_INFO'], '/') - self.assertFalse('bfg.routes.route' in request.environ) - self.assertFalse('bfg.routes.matchdict' in request.environ) - class DummyRequest: def __init__(self, environ=None): if environ is None: diff --git a/pyramid/tests/test_traversal.py b/pyramid/tests/test_traversal.py index 40893bfcf..237064871 100644 --- a/pyramid/tests/test_traversal.py +++ b/pyramid/tests/test_traversal.py @@ -71,8 +71,6 @@ class TraversalPathInfoTests(unittest.TestCase): self.assertEqual(self._callFUT('../../bar'), (text_('bar'),)) def test_segments_are_unicode(self): - # breaks because lru_cached holds on to strings? possibly from - # other tests. not good. result = self._callFUT('/foo/bar') self.assertEqual(type(result[0]), text_type) self.assertEqual(type(result[1]), text_type) @@ -162,7 +160,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): def test_call_pathel_with_no_getitem(self): policy = self._makeOne(None) environ = self._getEnviron() - request = DummyRequest(environ, path_info='/foo/bar') + request = DummyRequest(environ, path_info=text_('/foo/bar')) result = policy(request) self.assertEqual(result['context'], None) self.assertEqual(result['view_name'], 'foo') @@ -176,7 +174,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): root = DummyContext() policy = self._makeOne(root) environ = self._getEnviron() - request = DummyRequest(environ, path_info='') + request = DummyRequest(environ, path_info=text_('')) result = policy(request) self.assertEqual(result['context'], root) self.assertEqual(result['view_name'], '') @@ -191,7 +189,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): root = DummyContext(foo) policy = self._makeOne(root) environ = self._getEnviron() - request = DummyRequest(environ, path_info='/foo/bar') + request = DummyRequest(environ, path_info=text_('/foo/bar')) result = policy(request) self.assertEqual(result['context'], foo) self.assertEqual(result['view_name'], 'bar') @@ -206,7 +204,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): root = DummyContext(foo) policy = self._makeOne(root) environ = self._getEnviron() - request = DummyRequest(environ, path_info='/foo/bar/baz/buz') + request = DummyRequest(environ, path_info=text_('/foo/bar/baz/buz')) result = policy(request) self.assertEqual(result['context'], foo) self.assertEqual(result['view_name'], 'bar') @@ -221,7 +219,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): root = DummyContext(foo) policy = self._makeOne(root) environ = self._getEnviron() - request = DummyRequest(environ, path_info='/@@foo') + request = DummyRequest(environ, path_info=text_('/@@foo')) result = policy(request) self.assertEqual(result['context'], root) self.assertEqual(result['view_name'], 'foo') @@ -238,7 +236,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): foo = DummyContext(bar, 'foo') root = DummyContext(foo, 'root') policy = self._makeOne(root) - request = DummyRequest(environ, path_info='/baz') + request = DummyRequest(environ, path_info=text_('/baz')) result = policy(request) self.assertEqual(result['context'], baz) self.assertEqual(result['view_name'], '') @@ -257,7 +255,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): foo = DummyContext(bar, 'foo') root = DummyContext(foo, 'root') policy = self._makeOne(root) - request = DummyRequest(environ, path_info='/bar/baz') + request = DummyRequest(environ, path_info=text_('/bar/baz')) result = policy(request) self.assertEqual(result['context'], baz) self.assertEqual(result['view_name'], '') @@ -275,7 +273,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): foo = DummyContext(bar) root = DummyContext(foo) policy = self._makeOne(root) - request = DummyRequest(environ, path_info='/foo/bar/baz') + request = DummyRequest(environ, path_info=text_('/foo/bar/baz')) result = policy(request) self.assertEqual(result['context'], baz) self.assertEqual(result['view_name'], '') @@ -293,7 +291,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): foo = DummyContext(bar, 'foo') root = DummyContext(foo, 'root') policy = self._makeOne(root) - request = DummyRequest(environ, path_info='/') + request = DummyRequest(environ, path_info=text_('/')) result = policy(request) self.assertEqual(result['context'], baz) self.assertEqual(result['view_name'], '') @@ -308,7 +306,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): def test_call_with_vh_root_path_root(self): policy = self._makeOne(None) environ = self._getEnviron(HTTP_X_VHM_ROOT='/') - request = DummyRequest(environ, path_info='/') + request = DummyRequest(environ, path_info=text_('/')) result = policy(request) self.assertEqual(result['context'], None) self.assertEqual(result['view_name'], '') @@ -329,7 +327,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): else: vhm_root = b'/Qu\xc3\xa9bec' environ = self._getEnviron(HTTP_X_VHM_ROOT=vhm_root) - request = DummyRequest(environ, path_info='/bar') + request = DummyRequest(environ, path_info=text_('/bar')) result = policy(request) self.assertEqual(result['context'], bar) self.assertEqual(result['view_name'], '') @@ -351,7 +349,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): root = DummyContext(foo) policy = self._makeOne(root) environ = self._getEnviron() - toraise = UnicodeDecodeError('ascii', 'a', 2, 3, '5') + toraise = UnicodeDecodeError('ascii', b'a', 2, 3, '5') request = DummyRequest(environ, toraise=toraise) request.matchdict = None self.assertRaises(URLDecodeError, policy, request) @@ -403,7 +401,7 @@ class ResourceTreeTraverserTests(unittest.TestCase): def test_withroute_and_traverse_string(self): resource = DummyContext() traverser = self._makeOne(resource) - matchdict = {'traverse':'foo/bar'} + matchdict = {'traverse':text_('foo/bar')} request = DummyRequest({}) request.matchdict = matchdict result = traverser(request) @@ -1287,7 +1285,7 @@ class DummyRequest: matchdict = None matched_route = None - def __init__(self, environ=None, path_info='/', toraise=None): + def __init__(self, environ=None, path_info=text_('/'), toraise=None): if environ is None: environ = {} self.environ = environ diff --git a/pyramid/traversal.py b/pyramid/traversal.py index 975a63787..6832ce69a 100644 --- a/pyramid/traversal.py +++ b/pyramid/traversal.py @@ -614,6 +614,7 @@ else: _segment_cache[(segment, safe)] = result return result +slash = text_('/') @implementer(ITraverser) class ResourceTreeTraverser(object): @@ -629,17 +630,17 @@ class ResourceTreeTraverser(object): self.root = root def __call__(self, request): - matchdict = request.matchdict environ = request.environ + matchdict = request.matchdict if matchdict is not None: - path = matchdict.get('traverse', '/') or '/' + path = matchdict.get('traverse', slash) or slash if is_nonstr_iter(path): # this is a *traverse stararg (not a {traverse}) # routing has already decoded these elements, so we just # need to join them - path = '/'.join(path) or '/' + path = slash.join(path) or slash subpath = matchdict.get('subpath', ()) if not is_nonstr_iter(subpath): @@ -653,9 +654,10 @@ class ResourceTreeTraverser(object): subpath = () try: # empty if mounted under a path in mod_wsgi, for example - path = request.path_info + path = request.path_info or slash except KeyError: - path = '/' + # if environ['PATH_INFO'] is just not there + path = slash except UnicodeDecodeError as e: raise URLDecodeError(e.encoding, e.object, e.start, e.end, e.reason) @@ -674,7 +676,7 @@ class ResourceTreeTraverser(object): root = self.root ob = vroot = root - if vpath == '/': # invariant: vpath must not be empty + if vpath == slash: # invariant: vpath must not be empty # prevent a call to traversal_path if we know it's going # to return the empty tuple vpath_tuple = () @@ -39,7 +39,7 @@ install_requires=[ 'setuptools', 'Chameleon >= 1.2.3', 'Mako >= 0.3.6', # strict_undefined - 'WebOb >= 1.2dev', # response.text / py3 compat + 'WebOb >= 1.2b3', # request.path_info is unicode 'repoze.lru >= 0.4', # py3 compat 'zope.interface >= 3.8.0', # has zope.interface.registry 'zope.deprecation >= 3.5.0', # py3 compat |
