summaryrefslogtreecommitdiff
path: root/repoze/bfg/configuration.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2010-07-15 17:41:05 +0000
committerChris McDonough <chrism@agendaless.com>2010-07-15 17:41:05 +0000
commit208ee5a8d6409bcdce361009dee6a2e335de1679 (patch)
tree3e47bda8becf94ae96d4b705c410fd8a2a925ffb /repoze/bfg/configuration.py
parent6ef5b21bffe62c3ad6d276b36ba4229f681128ba (diff)
downloadpyramid-208ee5a8d6409bcdce361009dee6a2e335de1679.tar.gz
pyramid-208ee5a8d6409bcdce361009dee6a2e335de1679.tar.bz2
pyramid-208ee5a8d6409bcdce361009dee6a2e335de1679.zip
Features
-------- - New view predicate: match_val. The ``match_val`` value represents the presence of a value in the structure added to the request named ``matchdict`` during URL dispatch representing the match values from the route pattern (e.g. if the route pattern has ``:foo`` in it, and the route matches, a key will exist in the matchdict named ``foo``). Like all other view predicates, this feature is exposed via the ``bfg_view`` API, the Configurator ``add_view`` API, and the ZCML ``view`` directive. Documentation ------------- - API documentation for the ``add_view`` method of the configurator changed to include ``match_val``. - ZCML documentation for ``view`` ZCML directive changed to include ``match_val``. - The ``Views`` narrative chapter now contains a description of the ``match_val`` predicate. Bug Fixes --------- - The ``header`` predicate (when used as either a view predicate or a route predicate) had a problem when specified with a name/regex pair. When the header did not exist in the headers dictionary, the regex match could be fed ``None``, causing it to throw a ``TypeError: expected string or buffer`` exception. Now, the predicate returns False as intended. Internal -------- - Remove ``repoze.bfg.configuration.isclass`` function in favor of using ``inspect.isclass``.
Diffstat (limited to 'repoze/bfg/configuration.py')
-rw-r--r--repoze/bfg/configuration.py81
1 files changed, 66 insertions, 15 deletions
diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py
index 1e760a064..4073719b4 100644
--- a/repoze/bfg/configuration.py
+++ b/repoze/bfg/configuration.py
@@ -2,7 +2,6 @@ import os
import re
import sys
import threading
-import types
import inspect
from webob import Response
@@ -526,8 +525,8 @@ class Configurator(object):
request_type=None, route_name=None, request_method=None,
request_param=None, containment=None, attr=None,
renderer=None, wrapper=None, xhr=False, accept=None,
- header=None, path_info=None, custom_predicates=(),
- context=None, _info=u''):
+ header=None, path_info=None, match_val=None,
+ custom_predicates=(), context=None, _info=u''):
""" Add a :term:`view configuration` to the current
configuration state. Arguments to ``add_view`` are broken
down below into *predicate* arguments and *non-predicate*
@@ -746,6 +745,33 @@ class Configurator(object):
variable. If the regex matches, this predicate will be
``True``.
+
+ match_val
+
+ The ``match_val`` value represents the presence of a value
+ in the :term:`URL dispatch` structure added to the request
+ named ``matchdict``. ``matchdict`` represents the match
+ values from the route pattern (e.g. if the route pattern has
+ ``:foo`` in it, and the route matches, a key will exist in
+ the matchdict named ``foo``). If the value does not contain
+ a colon, the entire value will be considered to be the name
+ of a matchdict key (e.g. ``action``). If the value does
+ contain a ``:`` (colon), it will be considered a name/value
+ pair (e.g. ``action:generate.html`` or ``action:\w+.html``).
+ The right hand side following the colon should be a regular
+ expression.
+
+ If the value does not contain a colon, the key specified by
+ the name must be present in the URL dispatch matchdict for
+ this predicate to be true; the value of the key is ignored.
+ If the value does contain a colon, the name implied by the
+ right hand must be present in the matchdict *and* the
+ regular expression specified on the right hand side of the
+ colon must match the value for the name in the matchdict for
+ this predicate to be true.
+
+ .. note:: This feature is new as of :mod:`repoze.bfg` 1.3.
+
custom_predicates
This value should be a sequence of references to custom
@@ -796,18 +822,18 @@ class Configurator(object):
request_method=request_method, request_param=request_param,
containment=containment, attr=attr,
renderer=renderer, wrapper=wrapper, xhr=xhr, accept=accept,
- header=header, path_info=path_info, custom_predicates=(),
- context=context, _info=u''
+ header=header, path_info=path_info, match_val=match_val,
+ custom_predicates=(), context=context, _info=u''
)
view_info = deferred_views.setdefault(route_name, [])
view_info.append(info)
return
- order, predicates, phash = _make_predicates(
- xhr=xhr, request_method=request_method, path_info=path_info,
+ order, predicates, phash = _make_predicates(xhr=xhr,
+ request_method=request_method, path_info=path_info,
request_param=request_param, header=header, accept=accept,
containment=containment, request_type=request_type,
- custom=custom_predicates)
+ view_match_val=match_val, custom=custom_predicates)
derived_view = self._derive_view(view, permission, predicates, attr,
renderer, wrapper, name, accept, order,
@@ -1655,7 +1681,8 @@ class Configurator(object):
def _make_predicates(xhr=None, request_method=None, path_info=None,
request_param=None, header=None, accept=None,
- containment=None, request_type=None, custom=()):
+ containment=None, request_type=None,
+ view_match_val=None, custom=()):
# PREDICATES
# ----------
@@ -1708,7 +1735,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None,
if xhr:
def xhr_predicate(context, request):
return request.is_xhr
- weights.append(1 << 0)
+ weights.append(1 << 1)
predicates.append(xhr_predicate)
h.update('xhr:%r' % bool(xhr))
@@ -1755,6 +1782,8 @@ def _make_predicates(xhr=None, request_method=None, path_info=None,
if header_val is None:
return header_name in request.headers
val = request.headers.get(header_name)
+ if val is None:
+ return False
return header_val.match(val) is not None
weights.append(1 << 5)
predicates.append(header_predicate)
@@ -1781,11 +1810,34 @@ def _make_predicates(xhr=None, request_method=None, path_info=None,
predicates.append(request_type_predicate)
h.update('request_type:%r' % id(request_type))
+ if view_match_val is not None:
+ match_name = view_match_val
+ match_val = None
+ if ':' in match_name:
+ match_name, match_val = match_name.split(':', 1)
+ try:
+ match_val = re.compile(match_val)
+ except re.error, why:
+ raise ConfigurationError(why[0])
+ def view_match_val_predicate(context, request):
+ matchdict = getattr(request, 'matchdict', None)
+ if matchdict is None:
+ return False
+ if match_val is None:
+ return match_name in matchdict
+ val = matchdict.get(match_name)
+ if val is None:
+ return False
+ return match_val.match(val) is not None
+ weights.append(1 << 9)
+ predicates.append(view_match_val_predicate)
+ h.update('view_match_val:%r=%r' % (match_name, match_val))
+
if custom:
for num, predicate in enumerate(custom):
predicates.append(predicate)
h.update('custom%s:%r' % (num, id(predicate)))
- weights.append(1 << 9)
+ weights.append(1 << 10)
score = 0
for bit in weights:
@@ -2151,11 +2203,10 @@ def _attr_wrap(view, accept, order, phash):
decorate_view(attr_view, view)
return attr_view
-def isclass(o):
- return isinstance(o, (type, types.ClassType))
-
def isexception(o):
- return isinstance(o, Exception) or isclass(o) and issubclass(o, Exception)
+ return isinstance(o, Exception) or (
+ inspect.isclass(o) and issubclass(o, Exception)
+ )
# note that ``options`` is a b/w compat alias for ``settings`` and
# ``Configurator`` is a testing dep inj