diff options
| -rw-r--r-- | CHANGES.txt | 35 | ||||
| -rw-r--r-- | docs/glossary.rst | 22 | ||||
| -rw-r--r-- | docs/narr/viewconfig.rst | 14 | ||||
| -rw-r--r-- | pyramid/config/predicates.py | 21 | ||||
| -rw-r--r-- | pyramid/config/views.py | 17 | ||||
| -rw-r--r-- | pyramid/tests/test_config/test_predicates.py | 53 | ||||
| -rw-r--r-- | pyramid/view.py | 2 |
7 files changed, 144 insertions, 20 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 9b3ce1253..4baf81581 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,19 +1,6 @@ Next release ============ -Features --------- - -- Allow multiple values to be specified to the ``request_param`` view/route - predicate as a sequence. Previously only a single string value was allowed. - See https://github.com/Pylons/pyramid/pull/705 - -- Comments with references to documentation sections placed in scaffold - ``.ini`` files. - -- Added an HTTP Basic authentication policy - at ``pyramid.authentication.BasicAuthAuthenticationPolicy``. - Bug Fixes --------- @@ -40,6 +27,16 @@ Bug Fixes Features -------- +- Allow multiple values to be specified to the ``request_param`` view/route + predicate as a sequence. Previously only a single string value was allowed. + See https://github.com/Pylons/pyramid/pull/705 + +- Comments with references to documentation sections placed in scaffold + ``.ini`` files. + +- Added an HTTP Basic authentication policy + at ``pyramid.authentication.BasicAuthAuthenticationPolicy``. + - The Configurator ``testing_securitypolicy`` method now returns the policy object it creates. @@ -56,6 +53,18 @@ Features ``remembered`` value on the policy, which is the value of the ``principal`` argument it's called with when its ``remember`` method is called. +- New ``physical_path`` view predicate. If specified, this value should be a + string or a tuple representing the physical traversal path of the context + found via traversal for this predicate to match as true. For example: + ``physical_path='/'`` or ``physical_path='/a/b/c'`` or ``physical_path=('', + 'a', 'b', 'c')``. This is not a path prefix match or a regex, it's a + whole-path match. It's useful when you want to always potentially show a + view when some object is traversed to, but you can't be sure about what kind + of object it will be, so you can't use the ``context`` predicate. The + individual path elements inbetween slash characters or in tuple elements + should be the Unicode representation of the name of the resource and should + not be encoded in any way. + 1.4a2 (2012-09-27) ================== diff --git a/docs/glossary.rst b/docs/glossary.rst index 96dd826d1..adcf36f7c 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -481,10 +481,24 @@ Glossary :app:`Pyramid` to form a workflow system. virtual root - A resource object representing the "virtual" root of a request; this - is typically the physical root object (the object returned by the - application root factory) unless :ref:`vhosting_chapter` is in - use. + A resource object representing the "virtual" root of a request; this is + typically the :term:`physical root` object unless :ref:`vhosting_chapter` + is in use. + + physical root + The object returned by the application :term:`root factory`. Unlike the + the :term:`virtual root` of a request, it is not impacted by + :ref:`vhosting_chapter`: it will always be the actual object returned by + the root factory, never a subobject. + + physical path + The path required by a traversal which resolve a :term:`resource` starting + from the :term:`physical root`. For example, the physical path of the + ``abc`` subobject of the physical root object is ``/abc``. Physical paths + can also be specified as tuples where the first element is the empty + string (representing the root), and every other element is a Unicode + object, e.g. ``('', 'abc')``. Physical paths are also sometimes called + "traversal paths". lineage An ordered sequence of objects based on a ":term:`location` -aware" diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index 3c7897969..752e6ad72 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -417,6 +417,20 @@ configured view. .. versionadded:: 1.4a2 +``physical_path`` + If specified, this value should be a string or a tuple representing the + :term:`physical path` of the context found via traversal for this predicate + to match as true. For example: ``physical_path='/'`` or + ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``. This is + not a path prefix match or a regex, it's a whole-path match. It's useful + when you want to always potentially show a view when some object is traversed + to, but you can't be sure about what kind of object it will be, so you can't + use the ``context`` predicate. The individual path elements inbetween slash + characters or in tuple elements should be the Unicode representation of the + name of the resource and should not be encoded in any way. + + .. versionadded:: 1.4a3 + ``custom_predicates`` If ``custom_predicates`` is specified, it must be a sequence of references to custom predicate callables. Use custom predicates when no set of diff --git a/pyramid/config/predicates.py b/pyramid/config/predicates.py index 100c9454e..adbdcbbc0 100644 --- a/pyramid/config/predicates.py +++ b/pyramid/config/predicates.py @@ -2,15 +2,16 @@ import re from pyramid.exceptions import ConfigurationError +from pyramid.compat import is_nonstr_iter + from pyramid.traversal import ( find_interface, traversal_path, + resource_path_tuple ) from pyramid.urldispatch import _compile_route - from pyramid.util import object_description - from pyramid.session import check_csrf_token from .util import as_sorted_tuple @@ -250,3 +251,19 @@ class CheckCSRFTokenPredicate(object): return self.check_csrf_token(request, val, raises=False) return True +class PhysicalPathPredicate(object): + def __init__(self, val, config): + if is_nonstr_iter(val): + self.val = tuple(val) + else: + val = tuple(filter(None, val.split('/'))) + self.val = ('',) + val + + def text(self): + return 'physical_path = %s' % (self.val,) + + phash = text + + def __call__(self, context, request): + return resource_path_tuple(context) == self.val + diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 15263ad04..e52f9d64b 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -1014,6 +1014,22 @@ class ViewsConfiguratorMixin(object): .. versionadded:: 1.4a2 + physical_path + + If specified, this value should be a string or a tuple representing + the :term:`physical path` of the context found via traversal for this + predicate to match as true. For example: ``physical_path='/'`` or + ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``. + This is not a path prefix match or a regex, it's a whole-path match. + It's useful when you want to always potentially show a view when some + object is traversed to, but you can't be sure about what kind of + object it will be, so you can't use the ``context`` predicate. The + individual path elements inbetween slash characters or in tuple + elements should be the Unicode representation of the name of the + resource and should not be encoded in any way. + + .. versionadded:: 1.4a3 + custom_predicates This value should be a sequence of references to custom @@ -1370,6 +1386,7 @@ class ViewsConfiguratorMixin(object): ('request_type', p.RequestTypePredicate), ('match_param', p.MatchParamPredicate), ('check_csrf', p.CheckCSRFTokenPredicate), + ('physical_path', p.PhysicalPathPredicate), ('custom', p.CustomPredicate), ): self.add_view_predicate(name, factory) diff --git a/pyramid/tests/test_config/test_predicates.py b/pyramid/tests/test_config/test_predicates.py index 2f0ef4132..84d9b184d 100644 --- a/pyramid/tests/test_config/test_predicates.py +++ b/pyramid/tests/test_config/test_predicates.py @@ -381,6 +381,59 @@ class TestHeaderPredicate(unittest.TestCase): inst = self._makeOne(r'abc:\d+') self.assertEqual(inst.phash(), r'header abc=\d+') +class Test_PhysicalPathPredicate(unittest.TestCase): + def _makeOne(self, val, config): + from pyramid.config.predicates import PhysicalPathPredicate + return PhysicalPathPredicate(val, config) + + def test_text(self): + inst = self._makeOne('/', None) + self.assertEqual(inst.text(), "physical_path = ('',)") + + def test_phash(self): + inst = self._makeOne('/', None) + self.assertEqual(inst.phash(), "physical_path = ('',)") + + def test_it_call_val_tuple_True(self): + inst = self._makeOne(('', 'abc'), None) + root = Dummy() + root.__name__ = '' + root.__parent__ = None + context = Dummy() + context.__name__ = 'abc' + context.__parent__ = root + self.assertTrue(inst(context, None)) + + def test_it_call_val_list_True(self): + inst = self._makeOne(['', 'abc'], None) + root = Dummy() + root.__name__ = '' + root.__parent__ = None + context = Dummy() + context.__name__ = 'abc' + context.__parent__ = root + self.assertTrue(inst(context, None)) + + def test_it_call_val_str_True(self): + inst = self._makeOne('/abc', None) + root = Dummy() + root.__name__ = '' + root.__parent__ = None + context = Dummy() + context.__name__ = 'abc' + context.__parent__ = root + self.assertTrue(inst(context, None)) + + def test_it_call_False(self): + inst = self._makeOne('/', None) + root = Dummy() + root.__name__ = '' + root.__parent__ = None + context = Dummy() + context.__name__ = 'abc' + context.__parent__ = root + self.assertFalse(inst(context, None)) + class predicate(object): def __repr__(self): return 'predicate' diff --git a/pyramid/view.py b/pyramid/view.py index 76f466b83..51ded423c 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -170,7 +170,7 @@ class view_config(object): ``request_type``, ``route_name``, ``request_method``, ``request_param``, ``containment``, ``xhr``, ``accept``, ``header``, ``path_info``, ``custom_predicates``, ``decorator``, ``mapper``, ``http_cache``, - ``match_param``, ``csrf_token``, and ``predicates``. + ``match_param``, ``csrf_token``, ``physical_path``, and ``predicates``. The meanings of these arguments are the same as the arguments passed to :meth:`pyramid.config.Configurator.add_view`. If any argument is left |
