diff options
| author | Éric Araujo <earaujo@caravan.coop> | 2020-01-07 14:33:31 -0500 |
|---|---|---|
| committer | Éric Araujo <earaujo@caravan.coop> | 2020-01-07 14:33:31 -0500 |
| commit | 26d2d87bc2865a431b5eb30552c3eac4108b3a0c (patch) | |
| tree | 2bcecba6b70e79eb8d732d8eceeb5e3ff1d46ef1 | |
| parent | 5702c3c3a4357a6071c9ba624a89655209548336 (diff) | |
| download | pyramid-26d2d87bc2865a431b5eb30552c3eac4108b3a0c.tar.gz pyramid-26d2d87bc2865a431b5eb30552c3eac4108b3a0c.tar.bz2 pyramid-26d2d87bc2865a431b5eb30552c3eac4108b3a0c.zip | |
rewrite docs for custom predicates
| -rw-r--r-- | docs/narr/hooks.rst | 2 | ||||
| -rw-r--r-- | docs/narr/urldispatch.rst | 179 | ||||
| -rw-r--r-- | docs/narr/viewconfig.rst | 18 | ||||
| -rw-r--r-- | docs/quick_tour.rst | 2 | ||||
| -rw-r--r-- | src/pyramid/config/routes.py | 12 | ||||
| -rw-r--r-- | src/pyramid/config/views.py | 12 |
6 files changed, 120 insertions, 105 deletions
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4a594a8c9..fbb845447 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1564,7 +1564,7 @@ event type. self.val = val def text(self): - return 'path_startswith = %s' % (self.val,) + return 'request_path_startswith = %s' % (self.val,) phash = text diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 9372163e8..6dd8b1455 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -1087,11 +1087,8 @@ A convenience context manager exists to set the route prefix for any Custom Route Predicates ----------------------- -Each of the predicate callables fed to the ``custom_predicates`` argument of -:meth:`~pyramid.config.Configurator.add_route` must be a callable accepting two -arguments. The first argument passed to a custom predicate is a dictionary -conventionally named ``info``. The second argument is the current -:term:`request` object. +A predicate is a callable that accepts two arguments: a dictionary +conventionally named ``info``, and the current :term:`request` object. The ``info`` dictionary has a number of contained values, including ``match`` and ``route``. ``match`` is a dictionary which represents the arguments matched @@ -1100,52 +1097,73 @@ was matched (see :class:`pyramid.interfaces.IRoute` for the API of such a route object). ``info['match']`` is useful when predicates need access to the route match. -For example: +Imagine you want to define a route when a part of the URL matches some +specific values. You could define three view configurations, each one +with its own ``match_param`` value (see :ref:`predicate_view_args`), but +you want to think of it as one route, and associate it with one view. +See this code: .. code-block:: python :linenos: - def any_of(segment_name, *allowed): - def predicate(info, request): - if info['match'][segment_name] in allowed: - return True - return predicate + class AnyOfPredicate: + def __init__(self, val): + self.segment_name = val[0] + self.allowed = tuple(val[0:]) + + def text(self): + args = (self.segment_name,) + self.allowed + return 'any_of = %s' % (args,) + + phash = text + + def __call__(self, info, request): + return info['match'][self.segment_name] in self.allowed + - num_one_two_or_three = any_of('num', 'one', 'two', 'three') + config.add_route_predicate("any_of", AnyOfPredicate) + config.add_route('route_to_num', '/{num}', any_of=('num', 'one', 'two', 'three')) - config.add_route('route_to_num', '/{num}', - custom_predicates=(num_one_two_or_three,)) -The above ``any_of`` function generates a predicate which ensures that the +An instance of the class defined above is a predicate which ensures that the match value named ``segment_name`` is in the set of allowable values -represented by ``allowed``. We use this ``any_of`` function to generate a -predicate function named ``num_one_two_or_three``, which ensures that the -``num`` segment is one of the values ``one``, ``two``, or ``three`` , and use -the result as a custom predicate by feeding it inside a tuple to the -``custom_predicates`` argument to -:meth:`~pyramid.config.Configurator.add_route`. +represented by ``allowed``. We register this class as a *predicate +factory* with the ``any_of`` argument name, then we can use that new +keyword argument with :meth:`~pyramid.config.Configurator.add_route` to +have Pyramid instantiate the class (the ``('num', 'one', 'two', +'three')`` value is passed to the constructor as the argument ``val``) +and use the resulting instance as a custom predicate to check if +incoming requests match the route or not. A custom route predicate may also *modify* the ``match`` dictionary. For instance, a predicate might do some type conversion of values: .. code-block:: python - :linenos: + :linenos: + + class IntegersPredicate: + + def __init__(self, val): + self.segment_names = val + + def text(self): + return 'integers = %s' % (self.segment_names,) - def integers(*segment_names): - def predicate(info, request): - match = info['match'] - for segment_name in segment_names: - try: - match[segment_name] = int(match[segment_name]) - except (TypeError, ValueError): - pass - return True - return predicate + phash = text - ymd_to_int = integers('year', 'month', 'day') + def __call__(self, info, request): + match = info['match'] + for segment_name in self.segment_names: + try: + match[segment_name] = int(match[segment_name]) + except (TypeError, ValueError): + pass + return True - config.add_route('ymd', '/{year}/{month}/{day}', - custom_predicates=(ymd_to_int,)) + + config.add_route_predicate('integers', IntegersPredicate) + config.add_route('ymd', '/{year}/{month}/{day}', + integers=('year', 'month', 'day') Note that a conversion predicate is still a predicate, so it must return ``True`` or ``False``. A predicate that does *only* conversion, such as the one @@ -1157,18 +1175,26 @@ expressions specifying requirements for that marker. For instance: .. code-block:: python :linenos: - def integers(*segment_names): - def predicate(info, request): + class IntegersPredicate: + + def __init__(self, val): + self.segment_names = val + + def text(self): + return 'integers = %s' % (self.segment_names,) + + phash = text + + def __call__(self, info, request): match = info['match'] - for segment_name in segment_names: + for segment_name in self.segment_names: match[segment_name] = int(match[segment_name]) return True - return predicate - ymd_to_int = integers('year', 'month', 'day') + config.add_route_predicate('integers', IntegersPredicate) config.add_route('ymd', '/{year:\d+}/{month:\d+}/{day:\d+}', - custom_predicates=(ymd_to_int,)) + integers=('year', 'month', 'day') Now the try/except is no longer needed because the route will not match at all unless these markers match ``\d+`` which requires them to be valid digits for @@ -1199,61 +1225,42 @@ route in a set of route predicates: .. code-block:: python :linenos: - def twenty_ten(info, request): - if info['route'].name in ('ymd', 'ym', 'y'): - return info['match']['year'] == '2010' - - config.add_route('y', '/{year}', custom_predicates=(twenty_ten,)) - config.add_route('ym', '/{year}/{month}', custom_predicates=(twenty_ten,)) - config.add_route('ymd', '/{year}/{month}/{day}', - custom_predicates=(twenty_ten,)) - -The above predicate, when added to a number of route configurations ensures -that the year match argument is '2010' if and only if the route name is 'ymd', -'ym', or 'y'. - -You can also caption the predicates by setting the ``__text__`` attribute. This -will help you with the ``pviews`` command (see -:ref:`displaying_application_routes`) and the ``pyramid_debugtoolbar``. - -If a predicate is a class, just add ``__text__`` property in a standard manner. - -.. code-block:: python - :linenos: - - class DummyCustomPredicate1(object): - def __init__(self): - self.__text__ = 'my custom class predicate' + class TwentyTenPredicate: + def text(self): + return "twenty_ten = True" - class DummyCustomPredicate2(object): - __text__ = 'my custom class predicate' + phash = text -If a predicate is a method, you'll need to assign it after method declaration -(see `PEP 232 <https://www.python.org/dev/peps/pep-0232/>`_). + def __call__(self, info, request): + if info['route'].name in ('ymd', 'ym', 'y'): + return info['match']['year'] == '2010' -.. code-block:: python - :linenos: + config.add_route_predicate('twenty_ten', TwentyTenPredicate) + config.add_route('y', '/{year}', twenty_ten=True) + config.add_route('ym', '/{year}/{month}', twenty_ten=True) + config.add_route('ymd', '/{year}/{month}/{day}', twenty_ten=True) - def custom_predicate(): - pass - custom_predicate.__text__ = 'my custom method predicate' - -If a predicate is a classmethod, using ``@classmethod`` will not work, but you -can still easily do it by wrapping it in a classmethod call. +The above predicate, when added to a number of route configurations ensures +that the year match argument is ``'2010'`` if and only if the route name is +``'ymd'``, ``'ym'``, or ``'y'``. -.. code-block:: python - :linenos: +The ``text`` method is a way to caption the predicates. This +will help you with the ``pviews`` command (see +:ref:`displaying_application_routes`) and the +:term:`pyramid_debugtoolbar`. - def classmethod_predicate(): - pass - classmethod_predicate.__text__ = 'my classmethod predicate' - classmethod_predicate = classmethod(classmethod_predicate) +The ``phash`` method should return a string that uniquely identifies a +specific predicate (the name means *predicate hash*). A good way to do +that is to use the same argument name and value that in the call to +``add_route``, like in the examples above. -The same will work with ``staticmethod``, using ``staticmethod`` instead of -``classmethod``. +.. XXX add note about predicate matching for boolean custom predicates? .. seealso:: + See :ref:`registering_thirdparty_predicates` for more information about + custom view, route and subscriber predicates. + See also :class:`pyramid.interfaces.IRoute` for more API documentation about route objects. diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index 6a49e02a5..eb5233e84 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -317,6 +317,8 @@ Non-Predicate Arguments .. versionadded:: 1.8 +.. _predicate_view_args: + Predicate Arguments +++++++++++++++++++ @@ -506,20 +508,22 @@ configured view. ``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 predefined - predicates do what you need. Custom predicates can be combined with + custom predicate callables. Custom predicates can be combined with predefined predicates as necessary. Each custom predicate callable should accept two arguments, ``context`` and ``request``, and should return either ``True`` or ``False`` after doing arbitrary evaluation of the context resource and/or the request. If all callables return ``True``, the associated view callable will be considered viable for a given request. + This parameter is kept around for backward compatibility. - If ``custom_predicates`` is not specified, no custom predicates are used. + .. deprecated:: 1.5 + See section below for new-style custom predicates. -``predicates`` - Pass a key/value pair here to use a third-party predicate registered via - :meth:`pyramid.config.Configurator.add_view_predicate`. More than one - key/value pair can be used at the same time. See +``**predicates`` + Extra keyword parameters are used to invoke custom predicates, defined + in your app or by third-party packages extending Pyramid and registered via + :meth:`pyramid.config.Configurator.add_view_predicate`. Use custom predicates + when no set of predefined predicates do what you need. See :ref:`view_and_route_predicates` for more information about third-party predicates. diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index 062693d24..fdd135331 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -478,7 +478,7 @@ more to offer: - One route leading to multiple views, based on information in the request or data such as ``request_param``, ``request_method``, ``accept``, ``header``, - ``xhr``, ``containment``, and ``custom_predicates`` + ``xhr``, ``containment``, and custom predicates. .. seealso:: See also: :ref:`Quick Tutorial View Classes <qtut_view_classes>`, :ref:`Quick diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py index 44fbb9c46..cc3a87b2e 100644 --- a/src/pyramid/config/routes.py +++ b/src/pyramid/config/routes.py @@ -40,7 +40,7 @@ class RoutesConfiguratorMixin(object): inherit_slash=None, **predicates ): - """ Add a :term:`route configuration` to the current + r""" Add a :term:`route configuration` to the current configuration state, as well as possibly a :term:`view configuration` to be used to specify a :term:`view callable` that will be invoked when this route matches. The arguments @@ -283,6 +283,8 @@ class RoutesConfiguratorMixin(object): .. versionadded:: 1.4a4 + .. deprecated:: 2.0 + custom_predicates .. deprecated:: 1.5 @@ -302,14 +304,14 @@ class RoutesConfiguratorMixin(object): :ref:`custom_route_predicates` for more information about ``info``. - predicates + \*\*predicates - Pass a key/value pair here to use a third-party predicate + Pass extra keyword parameters to use custom or third-party predicates registered via :meth:`pyramid.config.Configurator.add_route_predicate`. More than - one key/value pair can be used at the same time. See + one custom predicate can be used at the same time. See :ref:`view_and_route_predicates` for more information about - third-party predicates. + custom predicates. .. versionadded:: 1.4 diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py index 2cc5e8144..20f20b5e8 100644 --- a/src/pyramid/config/views.py +++ b/src/pyramid/config/views.py @@ -266,7 +266,7 @@ class ViewsConfiguratorMixin(object): exception_only=False, **view_options ): - """ Add a :term:`view configuration` to the current + r""" Add a :term:`view configuration` to the current configuration state. Arguments to ``add_view`` are broken down below into *predicate* arguments and *non-predicate* arguments. Predicate arguments narrow the circumstances in @@ -723,6 +723,8 @@ class ViewsConfiguratorMixin(object): .. versionadded:: 1.4a4 + .. deprecated:: 2.0 + custom_predicates .. deprecated:: 1.5 @@ -740,14 +742,14 @@ class ViewsConfiguratorMixin(object): obsoletes this argument, but it is kept around for backwards compatibility. - view_options + \*\*view_options - Pass a key/value pair here to use a third-party predicate or set a - value for a view deriver. See + Pass extra keyword parameters to use custom or third-party predicates + or set a value for a view deriver. See :meth:`pyramid.config.Configurator.add_view_predicate` and :meth:`pyramid.config.Configurator.add_view_deriver`. See :ref:`view_and_route_predicates` for more information about - third-party predicates and :ref:`view_derivers` for information + custom predicates and :ref:`view_derivers` for information about view derivers. .. versionadded: 1.4a1 |
