diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-11-16 18:58:34 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-11-16 18:58:34 +0000 |
| commit | 58fdd1e948b7223cbcaf4fdceb159de200356d79 (patch) | |
| tree | 162985896bd8ff3e88069029caf55ed5b5e0ec1b /repoze/bfg/zcml.py | |
| parent | 131f5f3046eb71145ebeb2a05b90bd89ec829dd9 (diff) | |
| download | pyramid-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.py | 457 |
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; |
