From e333c2c2236cbfd11809ee393aa71be1b4846d88 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Jan 2011 17:25:34 -0500 Subject: Remove configurator.add_handler, handler-related functions and methods from pyramid.view, handler ZCML directive. This functionality is to be moved to a "pyramid_handlers" package. Fix add_directive to properly persist directives across configurator creations. --- CHANGES.txt | 18 +++ docs/api/config.rst | 2 - docs/zcml.rst | 1 - pyramid/config.py | 166 +------------------ pyramid/includes/meta.zcml | 6 - pyramid/tests/test_config.py | 369 +++---------------------------------------- pyramid/tests/test_view.py | 22 --- pyramid/tests/test_zcml.py | 80 ---------- pyramid/view.py | 11 -- pyramid/zcml.py | 68 -------- 10 files changed, 44 insertions(+), 699 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 27a723fb4..6d613fa3f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,6 +7,24 @@ Bug Fixes - URL Dispatch properly handles a '.*' or '*' appearing in a regex match when used inside brackets. Resolve Issue #90. +Backwards Incompatibilities +--------------------------- + +- The ``add_handler`` method of a Configurator has been removed from the + Pyramid core. Handlers are now a feature of the ``pyramid_handlers`` + package, which can be downloaded from PyPI. Documentation for the package + should be available via http://pylonsproject.org, which describes how to + get this method back after depending upon ``pyramid_handlers`` as an + ``install_requires`` dependency. + +- The ``pyramid.view.action`` decorator has been removed from the Pyramid + core. Handlers are now a feature of the ``pyramid_handlers`` package. It + should now be imported from ``pyramid_handlers`` e.g. ``from + pyramid_handlers import action``. + +- The ``handler`` ZCML directive has been removed. It is now a feature of + the ``pyramid_handlers`` package. + Features -------- diff --git a/docs/api/config.rst b/docs/api/config.rst index 51666f53f..b4f85c248 100644 --- a/docs/api/config.rst +++ b/docs/api/config.rst @@ -48,8 +48,6 @@ .. automethod:: add_translation_dirs - .. automethod:: add_handler - .. automethod:: add_view .. automethod:: derive_view diff --git a/docs/zcml.rst b/docs/zcml.rst index e5bbe5d4b..caced5c16 100644 --- a/docs/zcml.rst +++ b/docs/zcml.rst @@ -17,7 +17,6 @@ documentation is organized alphabetically by directive name. zcml/configure zcml/default_permission zcml/forbidden - zcml/handler zcml/include zcml/localenegotiator zcml/notfound diff --git a/pyramid/config.py b/pyramid/config.py index 9b8a7c191..f3323ae5d 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -303,9 +303,6 @@ class Configurator(object): session_factory=session_factory, default_view_mapper=default_view_mapper, ) - if hasattr(registry, '_directives'): - for name, directive in registry._directives.items(): - self.add_directive(name, directive) def _set_settings(self, mapping): settings = Settings(mapping or {}) @@ -599,9 +596,16 @@ class Configurator(object): if not hasattr(self.registry, '_directives'): self.registry._directives = {} self.registry._directives[name] = c + + def __getattr__(self, name): + # allow directive extension names to work + directives = getattr(self.registry, '_directives', {}) + c = directives.get(name) + if c is None: + raise AttributeError(name) c = action_method(c) m = types.MethodType(c, self, self.__class__) - setattr(self, name, m) + return m @classmethod def with_context(cls, context): @@ -956,136 +960,6 @@ class Configurator(object): self.manager.pop() return registry - @action_method - def add_handler(self, route_name, pattern, handler, action=None, **kw): - - """ Add a Pylons-style view handler. This function adds a - route and some number of views based on a handler object - (usually a class). - - ``route_name`` is the name of the route (to be used later in - URL generation). - - ``pattern`` is the matching pattern, - e.g. ``'/blog/{action}'``. ``pattern`` may be ``None``, in - which case the pattern of an existing route named the same as - ``route_name`` is used. If ``pattern`` is ``None`` and no - route named ``route_name`` exists, a ``ConfigurationError`` is - raised. - - ``handler`` is a dotted name of (or direct reference to) a - Python handler class, - e.g. ``'my.package.handlers.MyHandler'``. - - If ``{action}`` or ``:action`` is in - the pattern, the exposed methods of the handler will be used - as views. - - If ``action`` is passed, it will be considered the method name - of the handler to use as a view. - - Passing both ``action`` and having an ``{action}`` in the - route pattern is disallowed. - - Any extra keyword arguments are passed along to ``add_route``. - - See :ref:`views_chapter` for more explanatory documentation. - - This method returns the result of add_route.""" - handler = self.maybe_dotted(handler) - - if pattern is not None: - route = self.add_route(route_name, pattern, **kw) - else: - mapper = self.get_routes_mapper() - route = mapper.get_route(route_name) - if route is None: - raise ConfigurationError( - 'The "pattern" parameter may only be "None" when a route ' - 'with the route_name argument was previously registered. ' - 'No such route named %r exists' % route_name) - - pattern = route.pattern - - action_decorator = getattr(handler, '__action_decorator__', None) - if action_decorator is not None: - if hasattr(action_decorator, 'im_self'): - # instance methods have an im_self == None - # classmethods have an im_self == cls - # staticmethods have no im_self - # instances have no im_self - if action_decorator.im_self is not handler: - raise ConfigurationError( - 'The "__action_decorator__" attribute of a handler ' - 'must not be an instance method (must be a ' - 'staticmethod, classmethod, function, or an instance ' - 'which is a callable') - - path_has_action = ':action' in pattern or '{action}' in pattern - - if action and path_has_action: - raise ConfigurationError( - 'action= (%r) disallowed when an action is in the route ' - 'path %r' % (action, pattern)) - - if path_has_action: - autoexpose = getattr(handler, '__autoexpose__', r'[A-Za-z]+') - if autoexpose: - try: - autoexpose = re.compile(autoexpose).match - except (re.error, TypeError), why: - raise ConfigurationError(why[0]) - for method_name, method in inspect.getmembers( - handler, inspect.ismethod): - configs = getattr(method, '__exposed__', []) - if autoexpose and not configs: - if autoexpose(method_name): - configs = [{}] - for expose_config in configs: - # we don't want to mutate any dict in __exposed__, - # so we copy each - view_args = expose_config.copy() - action = view_args.pop('name', method_name) - preds = list(view_args.pop('custom_predicates', [])) - preds.append(ActionPredicate(action)) - view_args['custom_predicates'] = preds - self.add_view(view=handler, attr=method_name, - route_name=route_name, - decorator=action_decorator, **view_args) - else: - method_name = action - if method_name is None: - method_name = '__call__' - - # Scan the controller for any other methods with this action name - for meth_name, method in inspect.getmembers( - handler, inspect.ismethod): - configs = getattr(method, '__exposed__', [{}]) - for expose_config in configs: - # Don't re-register the same view if this method name is - # the action name - if meth_name == action: - continue - # We only reg a view if the name matches the action - if expose_config.get('name') != method_name: - continue - # we don't want to mutate any dict in __exposed__, - # so we copy each - view_args = expose_config.copy() - del view_args['name'] - self.add_view(view=handler, attr=meth_name, - route_name=route_name, - decorator=action_decorator, **view_args) - - # Now register the method itself - method = getattr(handler, method_name, None) - configs = getattr(method, '__exposed__', [{}]) - for expose_config in configs: - self.add_view(view=handler, attr=action, route_name=route_name, - decorator=action_decorator, **expose_config) - - return route - @action_method def add_view(self, view=None, name="", for_=None, permission=None, request_type=None, route_name=None, request_method=None, @@ -3118,30 +2992,6 @@ def requestonly(view, attr=None): return False - -class ActionPredicate(object): - action_name = 'action' - def __init__(self, action): - self.action = action - try: - self.action_re = re.compile(action + '$') - except (re.error, TypeError), why: - raise ConfigurationError(why[0]) - - def __call__(self, context, request): - matchdict = request.matchdict - if matchdict is None: - return False - action = matchdict.get(self.action_name) - if action is None: - return False - return bool(self.action_re.match(action)) - - def __hash__(self): - # allow this predicate's phash to be compared as equal to - # others that share the same action name - return hash(self.action) - class PyramidConfigurationMachine(ConfigurationMachine): autocommit = False diff --git a/pyramid/includes/meta.zcml b/pyramid/includes/meta.zcml index 9f3726cc9..e0a113ca3 100644 --- a/pyramid/includes/meta.zcml +++ b/pyramid/includes/meta.zcml @@ -34,12 +34,6 @@ handler="pyramid.zcml.route" /> - -