Permalink
Browse files

- 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.

- 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.
  • Loading branch information...
mcdonc committed Sep 9, 2012
1 parent def68d6 commit ebcdc7cccc977e388426f581abaf16e39c49cdbd
Showing with 52 additions and 44 deletions.
  1. +29 −0 CHANGES.txt
  2. +0 −9 pyramid/request.py
  3. +0 −12 pyramid/tests/test_request.py
  4. +14 −16 pyramid/tests/test_traversal.py
  5. +8 −6 pyramid/traversal.py
  6. +1 −1 setup.py
View
@@ -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.
+
View
@@ -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)
@@ -549,18 +549,6 @@ def test_subpath_path_info_and_script_name_have_utf8(self):
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:
@@ -71,8 +71,6 @@ def test_twodots_at_start(self):
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 @@ def test_call_with_pathinfo_highorder(self):
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 @@ def test_call_withconn_getitem_emptypath_nosubpath(self):
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 @@ def test_call_withconn_getitem_withpath_nosubpath(self):
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 @@ def test_call_withconn_getitem_withpath_withsubpath(self):
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 @@ def test_call_with_explicit_viewname(self):
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 @@ def test_call_with_vh_root(self):
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 @@ def test_call_with_vh_root2(self):
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 @@ def test_call_with_vh_root3(self):
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 @@ def test_call_with_vh_root4(self):
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 @@ def test_call_with_vh_root4(self):
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 @@ def test_call_with_vh_root_highorder(self):
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 @@ def test_path_info_raises_unicodedecodeerror(self):
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 @@ def test_withroute_with_subpath_tuple(self):
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
View
@@ -614,6 +614,7 @@ def quote_path_segment(segment, safe=''):
_segment_cache[(segment, safe)] = result
return result
+slash = text_('/')
@implementer(ITraverser)
class ResourceTreeTraverser(object):
@@ -629,17 +630,17 @@ def __init__(self, root):
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 @@ def __call__(self, request):
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 @@ def __call__(self, request):
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 = ()
View
@@ -39,7 +39,7 @@
'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

0 comments on commit ebcdc7c

Please sign in to comment.