summaryrefslogtreecommitdiff
path: root/repoze/bfg/zcml.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-11-16 18:58:34 +0000
committerChris McDonough <chrism@agendaless.com>2009-11-16 18:58:34 +0000
commit58fdd1e948b7223cbcaf4fdceb159de200356d79 (patch)
tree162985896bd8ff3e88069029caf55ed5b5e0ec1b /repoze/bfg/zcml.py
parent131f5f3046eb71145ebeb2a05b90bd89ec829dd9 (diff)
downloadpyramid-58fdd1e948b7223cbcaf4fdceb159de200356d79.tar.gz
pyramid-58fdd1e948b7223cbcaf4fdceb159de200356d79.tar.bz2
pyramid-58fdd1e948b7223cbcaf4fdceb159de200356d79.zip
Merge imperativeconfig branch.
Diffstat (limited to 'repoze/bfg/zcml.py')
-rw-r--r--repoze/bfg/zcml.py457
1 files changed, 128 insertions, 329 deletions
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index 0213e564c..7bfa1a916 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -1,16 +1,10 @@
-import re
-import sys
-
from zope.component import getSiteManager
-from zope.component import getUtility
from zope.component import queryUtility
from zope.configuration.exceptions import ConfigurationError
from zope.configuration.fields import GlobalObject
from zope.interface import Interface
-from zope.interface import implementedBy
-from zope.interface.interfaces import IInterface
from zope.schema import Bool
from zope.schema import Int
@@ -22,16 +16,11 @@ import martian
from repoze.bfg.interfaces import IAuthenticationPolicy
from repoze.bfg.interfaces import IAuthorizationPolicy
from repoze.bfg.interfaces import IForbiddenView
-from repoze.bfg.interfaces import IMultiView
from repoze.bfg.interfaces import INotFoundView
-from repoze.bfg.interfaces import IPackageOverrides
from repoze.bfg.interfaces import IRendererFactory
from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IRouteRequest
-from repoze.bfg.interfaces import IRoutesMapper
-from repoze.bfg.interfaces import ISecuredView
from repoze.bfg.interfaces import IView
-from repoze.bfg.interfaces import IViewPermission
from repoze.bfg.authentication import RepozeWho1AuthenticationPolicy
from repoze.bfg.authentication import RemoteUserAuthenticationPolicy
@@ -40,12 +29,8 @@ from repoze.bfg.authorization import ACLAuthorizationPolicy
from repoze.bfg.configuration import zcml_configure
from repoze.bfg.path import package_name
from repoze.bfg.request import route_request_iface
-from repoze.bfg.resource import PackageOverrides
from repoze.bfg.resource import resource_spec
from repoze.bfg.static import StaticRootFactory
-from repoze.bfg.traversal import find_interface
-from repoze.bfg.view import MultiView
-from repoze.bfg.view import derive_view
from repoze.bfg.view import static as static_view
###################### directives ##########################
@@ -148,104 +133,6 @@ class IViewDirective(Interface):
description=(u'Accepts a regular expression.'),
required = False)
-def _make_predicates(xhr=None, request_method=None, path_info=None,
- request_param=None, header=None, accept=None,
- containment=None):
- # Predicates are added to the predicate list in (presumed)
- # computation expense order. All predicates associated with a
- # view must evaluate true for the view to "match" a request.
- # Elsewhere in the code, we evaluate them using a generator
- # expression. The fastest predicate should be evaluated first,
- # then the next fastest, and so on, as if one returns false, the
- # remainder of the predicates won't need to be evaluated.
-
- # Each predicate is associated with a weight value. The weight
- # symbolizes the relative potential "importance" of the predicate
- # to all other predicates. A larger weight indicates greater
- # importance. These weights are subtracted from an aggregate
- # 'weight' variable. The aggregate weight is then divided by the
- # length of the predicate list to compute a "score" for this view.
- # The score represents the ordering in which a "multiview" ( a
- # collection of views that share the same context/request/name
- # triad but differ in other ways via predicates) will attempt to
- # call its set of views. Views with lower scores will be tried
- # first. The intent is to a) ensure that views with more
- # predicates are always evaluated before views with fewer
- # predicates and b) to ensure a stable call ordering of views that
- # share the same number of predicates.
-
- # Views which do not have any predicates get a score of
- # sys.maxint, meaning that they will be tried very last.
-
- predicates = []
- weight = sys.maxint
-
- if xhr:
- def xhr_predicate(context, request):
- return request.is_xhr
- weight = weight - 10
- predicates.append(xhr_predicate)
-
- if request_method is not None:
- def request_method_predicate(context, request):
- return request.method == request_method
- weight = weight - 20
- predicates.append(request_method_predicate)
-
- if path_info is not None:
- try:
- path_info_val = re.compile(path_info)
- except re.error, why:
- raise ConfigurationError(why[0])
- def path_info_predicate(context, request):
- return path_info_val.match(request.path_info) is not None
- weight = weight - 30
- predicates.append(path_info_predicate)
-
- if request_param is not None:
- request_param_val = None
- if '=' in request_param:
- request_param, request_param_val = request_param.split('=', 1)
- def request_param_predicate(context, request):
- if request_param_val is None:
- return request_param in request.params
- return request.params.get(request_param) == request_param_val
- weight = weight - 40
- predicates.append(request_param_predicate)
-
- if header is not None:
- header_name = header
- header_val = None
- if ':' in header:
- header_name, header_val = header.split(':', 1)
- try:
- header_val = re.compile(header_val)
- except re.error, why:
- raise ConfigurationError(why[0])
- def header_predicate(context, request):
- if header_val is None:
- return header_name in request.headers
- val = request.headers.get(header_name)
- return header_val.match(val) is not None
- weight = weight - 50
- predicates.append(header_predicate)
-
- if accept is not None:
- def accept_predicate(context, request):
- return accept in request.accept
- weight = weight - 60
- predicates.append(accept_predicate)
-
- if containment is not None:
- def containment_predicate(context, request):
- return find_interface(context, containment) is not None
- weight = weight - 70
- predicates.append(containment_predicate)
-
- # this will be == sys.maxint if no predicates
- score = weight / (len(predicates) + 1)
- return score, predicates
-
def view(
_context,
permission=None,
@@ -297,66 +184,129 @@ def view(
if renderer and '.' in renderer:
renderer = resource_spec(renderer, package_name(_context.resolve('.')))
- score, predicates = _make_predicates(
- xhr=xhr, request_method=request_method, path_info=path_info,
- request_param=request_param, header=header, accept=accept,
- containment=containment)
-
def register():
- derived_view = derive_view(view, permission, predicates, attr, renderer,
- wrapper, name)
- r_for_ = for_
- r_request_type = request_type
- if r_for_ is None:
- r_for_ = Interface
- if not IInterface.providedBy(r_for_):
- r_for_ = implementedBy(r_for_)
- if not IInterface.providedBy(r_request_type):
- r_request_type = implementedBy(r_request_type)
- old_view = sm.adapters.lookup((r_for_, r_request_type), IView,name=name)
- if old_view is None:
- if hasattr(derived_view, '__call_permissive__'):
- sm.registerAdapter(derived_view, (for_, request_type),
- ISecuredView, name, _context.info)
- if hasattr(derived_view, '__permitted__'):
- # bw compat
- sm.registerAdapter(derived_view.__permitted__,
- (for_, request_type), IViewPermission,
- name, _context.info)
- else:
- sm.registerAdapter(derived_view, (for_, request_type),
- IView, name, _context.info)
- else:
- # XXX we could try to be more efficient here and register
- # a non-secured view for a multiview if none of the
- # multiview's consituent views have a permission
- # associated with them, but this code is getting pretty
- # rough already
- if IMultiView.providedBy(old_view):
- multiview = old_view
- else:
- multiview = MultiView(name)
- multiview.add(old_view, sys.maxint)
- multiview.add(derived_view, score)
- for i in (IView, ISecuredView):
- # unregister any existing views
- sm.adapters.unregister((r_for_, r_request_type), i, name=name)
- sm.registerAdapter(multiview, (for_, request_type), IMultiView,
- name, _context.info)
- # b/w compat
- sm.registerAdapter(multiview.__permitted__,
- (for_, request_type), IViewPermission,
- name, _context.info)
+ sm.view(permission=permission, for_=for_, view=view, name=name,
+ request_type=request_type, route_name=route_name,
+ 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, _info=_context.info)
+
_context.action(
discriminator = ('view', for_, name, request_type, IView, containment,
request_param, request_method, route_name, attr,
xhr, accept, header, path_info),
callable = register,
- args = (),
)
_view = view # for directives that take a view arg
+class IRouteDirective(Interface):
+ """ The interface for the ``route`` ZCML directive
+ """
+ name = TextLine(title=u'name', required=True)
+ path = TextLine(title=u'path', required=True)
+ factory = GlobalObject(title=u'context factory', required=False)
+ view = GlobalObject(title=u'view', required=False)
+
+ view_for = GlobalObject(title=u'view_for', required=False)
+ # alias for view_for
+ for_ = GlobalObject(title=u'for', required=False)
+
+ view_permission = TextLine(title=u'view_permission', required=False)
+ # alias for view_permission
+ permission = TextLine(title=u'permission', required=False)
+
+ view_request_type = TextLine(title=u'view_request_type', required=False)
+ # alias for view_request_type
+ request_type = TextLine(title=u'request_type', required=False)
+
+ view_renderer = TextLine(title=u'view_renderer', required=False)
+ # alias for view_renderer
+ renderer = TextLine(title=u'renderer', required=False)
+
+ view_request_method = TextLine(title=u'view_request_method', required=False)
+ view_containment = GlobalObject(
+ title = u'Dotted name of a containment class or interface',
+ required=False)
+ view_attr = TextLine(title=u'view_attr', required=False)
+ view_header = TextLine(title=u'view_header', required=False)
+ view_accept = TextLine(title=u'view_accept', required=False)
+ view_xhr = Bool(title=u'view_xhr', required=False)
+ view_path_info = TextLine(title=u'view_path_info', required=False)
+
+ request_method = TextLine(title=u'request_method', required=False)
+ request_param = TextLine(title=u'request_param', required=False)
+ header = TextLine(title=u'header', required=False)
+ accept = TextLine(title=u'accept', required=False)
+ xhr = Bool(title=u'xhr', required=False)
+ path_info = TextLine(title=u'path_info', required=False)
+
+def route(_context, name, path, view=None, view_for=None,
+ permission=None, factory=None, request_type=None, for_=None,
+ header=None, xhr=False, accept=None, path_info=None,
+ request_method=None, request_param=None,
+ view_permission=None, view_request_type=None,
+ view_request_method=None, view_request_param=None,
+ view_containment=None, view_attr=None,
+ renderer=None, view_renderer=None, view_header=None,
+ view_accept=None, view_xhr=False,
+ view_path_info=None):
+ """ Handle ``route`` ZCML directives
+ """
+ # the strange ordering of the request kw args above is for b/w
+ # compatibility purposes.
+ # these are route predicates; if they do not match, the next route
+ # in the routelist will be tried
+ sm = getSiteManager()
+
+ if request_type in ('GET', 'HEAD', 'PUT', 'POST', 'DELETE'):
+ # b/w compat for 1.0
+ view_request_method = request_type
+ request_type = None
+
+ request_iface = queryUtility(IRouteRequest, name=name)
+ if request_iface is None:
+ request_iface = route_request_iface(name)
+ sm.registerUtility(request_iface, IRouteRequest, name=name)
+
+ if view:
+ view_for = view_for or for_
+ view_request_type = view_request_type or request_type
+ view_permission = view_permission or permission
+ view_renderer = view_renderer or renderer
+ _view(
+ _context,
+ permission=view_permission,
+ for_=view_for,
+ view=view,
+ name='',
+ request_type=view_request_type,
+ route_name=name,
+ request_method=view_request_method,
+ request_param=view_request_param,
+ containment=view_containment,
+ attr=view_attr,
+ renderer=view_renderer,
+ header=view_header,
+ accept=view_accept,
+ xhr=view_xhr,
+ path_info=view_path_info,
+ )
+
+ def register():
+ sm.route(name, path, factory=factory, header=header,
+ xhr=xhr, accept=accept, path_info=path_info,
+ request_method=request_method, request_param=request_param,
+ _info=_context.info)
+
+ _context.action(
+ discriminator = ('route', name, xhr, request_method, path_info,
+ request_param, header, accept),
+ callable = register,
+ )
+
+
class ISystemViewDirective(Interface):
view = GlobalObject(
title=u"",
@@ -398,10 +348,8 @@ def view_utility(_context, view, attr, renderer, wrapper, iface):
renderer = resource_spec(renderer, package_name(_context.resolve('.')))
def register():
- derived_view = derive_view(view, attr=attr, renderer_name=renderer,
- wrapper_viewname=wrapper)
sm = getSiteManager()
- sm.registerUtility(derived_view, iface, '', _context.info)
+ sm.view_utility(view, attr, renderer, wrapper, iface, _context.info)
_context.action(
discriminator = iface,
@@ -422,19 +370,7 @@ class IResourceDirective(Interface):
description=u"The spec of the resource providing the override.",
required=True)
-def _override(package, path, override_package, override_prefix,
- PackageOverrides=PackageOverrides):
- # PackageOverrides kw arg for tests
- sm = getSiteManager()
- pkg_name = package.__name__
- override_pkg_name = override_package.__name__
- override = queryUtility(IPackageOverrides, name=pkg_name)
- if override is None:
- override = PackageOverrides(package)
- sm.registerUtility(override, IPackageOverrides, name=pkg_name)
- override.insert(path, override_pkg_name, override_prefix)
-
-def resource(context, to_override, override_with):
+def resource(_context, to_override, override_with):
if to_override == override_with:
raise ConfigurationError('You cannot override a resource with itself')
@@ -460,13 +396,12 @@ def resource(context, to_override, override_with):
'A file cannot be overridden with a directory (put a slash '
'at the end of to_override if necessary)')
- package = context.resolve(package)
- override_package = context.resolve(override_package)
+ sm = getSiteManager()
- context.action(
+ _context.action(
discriminator = None,
- callable = _override,
- args = (package, path, override_package, override_prefix),
+ callable = sm.resource,
+ args = (to_override, override_with, _context.info),
)
class IRepozeWho1AuthenticationPolicyDirective(Interface):
@@ -481,7 +416,7 @@ def repozewho1authenticationpolicy(_context, identifier_name='auth_tkt',
# authentication policies must be registered eagerly so they can
# be found by the view registration machinery
sm = getSiteManager()
- sm.registerUtility(policy, IAuthenticationPolicy)
+ sm.authentication_policy(policy, _info=_context.info)
_context.action(discriminator=IAuthenticationPolicy)
class IRemoteUserAuthenticationPolicyDirective(Interface):
@@ -496,7 +431,7 @@ def remoteuserauthenticationpolicy(_context, environ_key='REMOTE_USER',
# authentication policies must be registered eagerly so they can
# be found by the view registration machinery
sm = getSiteManager()
- sm.registerUtility(policy, IAuthenticationPolicy)
+ sm.authentication_policy(policy, _info=_context.info)
_context.action(discriminator=IAuthenticationPolicy)
class IAuthTktAuthenticationPolicyDirective(Interface):
@@ -533,7 +468,7 @@ def authtktauthenticationpolicy(_context,
# authentication policies must be registered eagerly so they can
# be found by the view registration machinery
sm = getSiteManager()
- sm.registerUtility(policy, IAuthenticationPolicy)
+ sm.authentication_policy(policy, _info=_context.info)
_context.action(discriminator=IAuthenticationPolicy)
class IACLAuthorizationPolicyDirective(Interface):
@@ -544,120 +479,9 @@ def aclauthorizationpolicy(_context):
# authorization policies must be registered eagerly so they can be
# found by the view registration machinery
sm = getSiteManager()
- sm.registerUtility(policy, IAuthorizationPolicy)
+ sm.authorization_policy(policy, _info=_context.info)
_context.action(discriminator=IAuthorizationPolicy)
-class IRouteDirective(Interface):
- """ The interface for the ``route`` ZCML directive
- """
- name = TextLine(title=u'name', required=True)
- path = TextLine(title=u'path', required=True)
- factory = GlobalObject(title=u'context factory', required=False)
- view = GlobalObject(title=u'view', required=False)
-
- view_for = GlobalObject(title=u'view_for', required=False)
- # alias for view_for
- for_ = GlobalObject(title=u'for', required=False)
-
- view_permission = TextLine(title=u'view_permission', required=False)
- # alias for view_permission
- permission = TextLine(title=u'permission', required=False)
-
- view_request_type = TextLine(title=u'view_request_type', required=False)
- # alias for view_request_type
- request_type = TextLine(title=u'request_type', required=False)
-
- view_renderer = TextLine(title=u'view_renderer', required=False)
- # alias for view_renderer
- renderer = TextLine(title=u'renderer', required=False)
-
- view_request_method = TextLine(title=u'view_request_method', required=False)
- view_containment = GlobalObject(
- title = u'Dotted name of a containment class or interface',
- required=False)
- view_attr = TextLine(title=u'view_attr', required=False)
- view_header = TextLine(title=u'view_header', required=False)
- view_accept = TextLine(title=u'view_accept', required=False)
- view_xhr = Bool(title=u'view_xhr', required=False)
- view_path_info = TextLine(title=u'view_path_info', required=False)
-
- request_method = TextLine(title=u'request_method', required=False)
- request_param = TextLine(title=u'request_param', required=False)
- header = TextLine(title=u'header', required=False)
- accept = TextLine(title=u'accept', required=False)
- xhr = Bool(title=u'xhr', required=False)
- path_info = TextLine(title=u'path_info', required=False)
-
-def route(_context, name, path, view=None, view_for=None,
- permission=None, factory=None, request_type=None, for_=None,
- header=None, xhr=False, accept=None, path_info=None,
- request_method=None, request_param=None,
- view_permission=None, view_request_type=None,
- view_request_method=None, view_request_param=None,
- view_containment=None, view_attr=None,
- renderer=None, view_renderer=None, view_header=None,
- view_accept=None, view_xhr=False,
- view_path_info=None):
- """ Handle ``route`` ZCML directives
- """
- # the strange ordering of the request kw args above is for b/w
- # compatibility purposes.
- # these are route predicates; if they do not match, the next route
- # in the routelist will be tried
- _, predicates = _make_predicates(xhr=xhr,
- request_method=request_method,
- path_info=path_info,
- request_param=request_param,
- header=header,
- accept=accept)
-
- sm = getSiteManager()
-
- if request_type in ('GET', 'HEAD', 'PUT', 'POST', 'DELETE'):
- # b/w compat for 1.0
- view_request_method = request_type
- request_type = None
-
- request_iface = queryUtility(IRouteRequest, name=name)
- if request_iface is None:
- request_iface = route_request_iface(name)
- sm.registerUtility(request_iface, IRouteRequest, name=name)
-
- if view:
- view_for = view_for or for_
- view_request_type = view_request_type or request_type
- view_permission = view_permission or permission
- view_renderer = view_renderer or renderer
- _view(
- _context,
- permission=view_permission,
- for_=view_for,
- view=view,
- name='',
- request_type=view_request_type,
- route_name=name,
- request_method=view_request_method,
- request_param=view_request_param,
- containment=view_containment,
- attr=view_attr,
- renderer=view_renderer,
- header=view_header,
- accept=view_accept,
- xhr=view_xhr,
- path_info=view_path_info,
- )
-
- _context.action(
- discriminator = ('route', name, xhr, request_method, path_info,
- request_param, header, accept),
- callable = connect_route,
- args = (path, name, factory, predicates),
- )
-
-def connect_route(path, name, factory, predicates):
- mapper = getUtility(IRoutesMapper)
- mapper.connect(path, name, factory, predicates=predicates)
-
class IRendererDirective(Interface):
factory = GlobalObject(
title=u'IRendererFactory implementation',
@@ -671,7 +495,7 @@ def renderer(_context, factory, name=''):
# renderer factories must be registered eagerly so they can be
# found by the view machinery
sm = getSiteManager()
- sm.registerUtility(factory, IRendererFactory, name=name)
+ sm.renderer(factory, name, _info=_context.info)
_context.action(discriminator=(IRendererFactory, name))
class IStaticDirective(Interface):
@@ -709,35 +533,10 @@ class IScanDirective(Interface):
def scan(_context, package, martian=martian):
# martian overrideable only for unit tests
- multi_grokker = BFGMultiGrokker()
- multi_grokker.register(BFGViewGrokker())
- module_grokker = martian.ModuleGrokker(grokker=multi_grokker)
- martian.grok_dotted_name(package.__name__, grokker=module_grokker,
- context=_context, exclude_filter=exclude)
-
-################# utility stuff ####################
-
-class BFGViewMarker(object):
- pass
-
-class BFGMultiGrokker(martian.core.MultiInstanceOrClassGrokkerBase):
- def get_bases(self, obj):
- if hasattr(obj, '__bfg_view_settings__'):
- return [BFGViewMarker]
- return []
-
-class BFGViewGrokker(martian.InstanceGrokker):
- martian.component(BFGViewMarker)
- def grok(self, name, obj, **kw):
- config = getattr(obj, '__bfg_view_settings__', [])
- for settings in config:
- view(kw['context'], view=obj, **settings)
- return bool(config)
-
-def exclude(name):
- if name.startswith('.'):
- return True
- return False
+ def register():
+ sm = getSiteManager()
+ sm.scan(package, _info=_context.info, martian=martian)
+ _context.action(discriminator=None, callable=register)
class Uncacheable(object):
""" Include in discriminators of actions which are not cacheable;