Beispiel #1
0
    def notify(self, hook_name, args=None, kwargs=None, controller=None, context_config=None):
        """Notifies a TurboGears hook.

        Each function registered for the given hook will be executed,
        ``args`` and ``kwargs`` will be passed to the registered functions
        as arguments.

        It permits to notify both application hooks::

            tg.hooks.notify('custom_global_hook')

        Or controller hooks::

            tg.hooks.notify('before_render', args=(remainder, params, output),
                            controller=RootController.index)

        """
        if context_config is None: #pragma: no cover
            context_config = tg.config._current_obj()

        args = args or []
        kwargs = kwargs or {}

        try:
            syswide_hooks = context_config['hooks'][hook_name]
            for func in syswide_hooks:
                func(*args, **kwargs)
        except KeyError: #pragma: no cover
            pass

        if controller is not None:
            controller = default_im_func(controller)
            deco = Decoration.get_decoration(controller)
            for func in deco.hooks.get(hook_name, []):
                func(*args, **kwargs)
Beispiel #2
0
def override_template(view, template):
    """Override the template to be used.

    Use override_template in a controller method in order to change the template
    that will be used to render the response dictionary dynamically.

    The ``view`` argument is the actual controller method for which you
    want to replace the template.

    The ``template`` string passed in requires that
    you include the template engine name, even if you're using the default.

    So you have to pass in a template id string like::

       "genshi:myproject.templates.index2"

    future versions may make the `genshi:` optional if you want to use
    the default engine.

    """
    try:
        engines = view.decoration.engines
    except:
        return

    for content_type, content_engine in engines.items():
        tmpl = template.split(':', 1)
        tmpl.extend(content_engine[2:])
        try:
            override_mapping = request._override_mapping
        except AttributeError:
            override_mapping = request._override_mapping = {}
        override_mapping.setdefault(default_im_func(view), {}).update({content_type: tmpl})
Beispiel #3
0
def override_template(controller, template):
    """Override the template to be used.

    Use override_template in a controller in order to change the template
    that will be used to render the response dictionary dynamically.

    The template string passed in requires that
    you include the template engine name, even if you're using the default.

    So you have to pass in a template id string like::

       "genshi:myproject.templates.index2"

    future versions may make the `genshi:` optional if you want to use
    the default engine.

    """
    try:
        engines = controller.decoration.engines
    except:
        return

    for content_type, content_engine in engines.items():
        tmpl = template.split(':', 1)
        tmpl.extend(content_engine[2:])
        try:
            override_mapping = request._override_mapping
        except AttributeError:
            override_mapping = request._override_mapping = {}
        override_mapping.setdefault(default_im_func(controller), {}).update({content_type: tmpl})
Beispiel #4
0
    def register(self, hook_name, func, controller=None):
        """Registers a TurboGears hook.

        Given an hook name and a function it registers the provided
        function for that role. For a complete list of hooks
        provided by default have a look at :ref:`hooks_and_events`.

        It permits to register hooks both application wide
        or for specific controllers::

            tg.hooks.register('before_render', hook_func, controller=RootController.index)
            tg.hooks.register('startup', startup_function)

        """
        if hook_name in ('startup', 'shutdown') and controller is not None:
            raise TGConfigError('Startup and Shutdown hooks cannot be registered on controllers')

        if hook_name == 'controller_wrapper':
            raise TGConfigError('tg.hooks.wrap_controller must be used to register wrappers')

        if controller is None:
            config_ready.register(_ApplicationHookRegistration(hook_name, func))
        else:
            controller = default_im_func(controller)
            renderers_ready.register(_ControllerHookRegistration(controller, hook_name, func))
Beispiel #5
0
    def register(self, hook_name, func, controller=None):
        """Registers a TurboGears hook.

        Given an hook name and a function it registers the provided
        function for that role. For a complete list of hooks
        provided by default have a look at :ref:`hooks_and_events`.

        It permits to register hooks both application wide
        or for specific controllers::

            tg.hooks.register('before_render', hook_func, controller=RootController.index)
            tg.hooks.register('startup', startup_function)

        """
        if hook_name in ('startup', 'shutdown') and controller is not None:
            raise TGConfigError(
                'Startup and Shutdown hooks cannot be registered on controllers'
            )

        if hook_name == 'controller_wrapper':
            raise TGConfigError(
                'tg.hooks.wrap_controller must be used to register wrappers')

        if controller is None:
            config_ready.register(_ApplicationHookRegistration(
                hook_name, func))
        else:
            controller = default_im_func(controller)
            renderers_ready.register(
                _ControllerHookRegistration(controller, hook_name, func))
Beispiel #6
0
    def notify_with_value(self, hook_name, value, controller=None, context_config=None):
        """Notifies a TurboGears hook which is expected to return a value.

        hooks with values are expected to accept an input value an return
        a replacement for it. Each registered function will receive as input
        the value returned by the previous function in chain.

        The resulting value will be returned by the ``notify_with_value``
        call itself::

            app = tg.hooks.notify_with_value('before_config', app)

        """
        if context_config is None: #pragma: no cover
            context_config = tg.config._current_obj()

        try:
            syswide_hooks = context_config['hooks'][hook_name]
            for func in syswide_hooks:
                value = func(value)
        except KeyError: #pragma: no cover
            pass

        if controller is not None:
            controller = default_im_func(controller)
            deco = Decoration.get_decoration(controller)
            for func in deco.hooks[hook_name]:
                value = func(value)

        return value
Beispiel #7
0
    def notify_with_value(self,
                          hook_name,
                          value,
                          controller=None,
                          context_config=None):
        """Notifies a TurboGears hook which is expected to return a value.

        hooks with values are expected to accept an input value an return
        a replacement for it. Each registered function will receive as input
        the value returned by the previous function in chain.

        The resulting value will be returned by the ``notify_with_value``
        call itself::

            app = tg.hooks.notify_with_value('before_config', app)

        """
        if context_config is None:  # pragma: no cover
            context_config = tg.config._current_obj()

        try:
            syswide_hooks = context_config['hooks'][hook_name]
        except KeyError:  # pragma: no cover
            pass
        else:
            for func in syswide_hooks:
                value = func(value)

        if controller is not None:
            controller = default_im_func(controller)
            deco = Decoration.get_decoration(controller)
            for func in deco.hooks[hook_name]:
                value = func(value)

        return value
Beispiel #8
0
    def _process_validation_errors(cls, controller, remainder, params,
                                   exception, context):
        """Process validation errors.

        Sets up validation status and error tracking
        to assist generating a form with given values
        and the validation failure messages.

        The error handler in decoration.validation.error_handler resolved
        and returned to be called as a controller.
        If an error_handler isn't given, the original controller is returned instead.

        """
        req = context.request

        validation_status = req.validation
        validation_status['exception'] = exception

        if isinstance(exception, _Tw2ValidationError):
            #Fetch all the children and grandchildren of a widget
            widget = exception.widget
            widget_children = _navigate_tw2form_children(widget.child)

            errors = dict((child.compound_key, child.error_msg)
                          for child in widget_children)
            validation_status['errors'] = errors
            validation_status['values'] = widget.child.value
        elif isinstance(exception, TGValidationError):
            validation_status['errors'] = exception.error_dict
            validation_status['values'] = exception.value
        else:
            # Most Invalid objects come back with a list of errors in the format:
            #"fieldname1: error\nfieldname2: error"
            error_list = exception.__str__().split('\n')
            for error in error_list:
                field_value = list(map(strip_string, error.split(':', 1)))

                #if the error has no field associated with it,
                #return the error as a global form error
                if len(field_value) == 1:
                    validation_status['errors']['_the_form'] = field_value[0]
                    continue

                validation_status['errors'][field_value[0]] = field_value[1]

            validation_status['values'] = getattr(exception, 'value', {})

        deco = controller.decoration

        error_handler = deco.validation.error_handler
        if error_handler is None:
            error_handler = default_im_func(controller)

        validation_status['error_handler'] = error_handler
        return im_self(controller), error_handler
Beispiel #9
0
    def _process_validation_errors(cls, controller, remainder, params, exception, context):
        """Process validation errors.

        Sets up validation status and error tracking
        to assist generating a form with given values
        and the validation failure messages.

        The error handler in decoration.validation.error_handler resolved
        and returned to be called as a controller.
        If an error_handler isn't given, the original controller is returned instead.

        """
        req = context.request

        validation_status = req.validation
        validation_status.exception = exception

        if isinstance(exception, _Tw2ValidationError):
            # Fetch all the children and grandchildren of a widget
            widget = exception.widget
            widget_children = _navigate_tw2form_children(widget.child)

            errors = dict((child.compound_key, child.error_msg) for child in widget_children)
            validation_status.errors = errors
            validation_status.values = widget.child.value
        elif isinstance(exception, TGValidationError):
            validation_status.errors = exception.error_dict
            validation_status.values = exception.value
        else:
            # Most Invalid objects come back with a list of errors in the format:
            # "fieldname1: error\nfieldname2: error"
            error_list = exception.__str__().split('\n')
            for error in error_list:
                field_value = list(map(strip_string, error.split(':', 1)))

                #if the error has no field associated with it,
                #return the error as a global form error
                if len(field_value) == 1:
                    validation_status.errors['_the_form'] = field_value[0]
                    continue

                validation_status.errors[field_value[0]] = field_value[1]

            validation_status.values = getattr(exception, 'value', {})

        # Get the error handler associated to the current validation status.
        error_handler = validation_status.error_handler
        chain_validation = validation_status.chain_validation
        if error_handler is None:
            error_handler = default_im_func(controller)
            chain_validation = False

        return im_self(controller), error_handler, chain_validation
Beispiel #10
0
def use_custom_format(controller, custom_format):
    """Use use_custom_format in a controller in order to change
    the active @expose decorator when available."""
    deco = Decoration.get_decoration(controller)

    # Check the custom_format passed is available for use
    if custom_format not in deco.custom_engines:
        raise ValueError("'%s' is not a valid custom_format" % custom_format)

    try:
        render_custom_format = request._render_custom_format
    except AttributeError:
        render_custom_format = request._render_custom_format = {}
    render_custom_format[default_im_func(controller)] = custom_format
Beispiel #11
0
def use_custom_format(controller, custom_format):
    """Use use_custom_format in a controller in order to change
    the active @expose decorator when available."""
    deco = Decoration.get_decoration(controller)

    # Check the custom_format passed is available for use
    if custom_format not in deco.custom_engines:
        raise ValueError("'%s' is not a valid custom_format" % custom_format)

    try:
        render_custom_format = request._render_custom_format
    except AttributeError:
        render_custom_format = request._render_custom_format = {}
    render_custom_format[default_im_func(controller)] = custom_format
Beispiel #12
0
    def setUp(self):
        TestWSGIController.setUp(self)
        tg.config.update({
            'paths': {'root': data_dir},
            'package': tests,
        })

        # Mimic configuration of a controller wrapper, this is required as
        # TestWSGIController doesn't actually create an AppConfig
        # so configurations don't get resolved.
        cwrapper = ControllerWrapperForErrorHandler(None, call_controller)
        wrappers_conf = {default_im_func(BasicTGController.hooked_error_handler): cwrapper}
        tg.config.update({'dedicated_controller_wrappers': wrappers_conf})

        self.app = make_app(BasicTGController)
Beispiel #13
0
    def wrap_controller(self, func, controller=None):
        """Registers a TurboGears controller wrapper.

        Controller Wrappers are much like a **decorator** applied to
        every controller.
        They receive :class:`tg.configuration.AppConfig` instance
        as an argument and the next handler in chain and are expected
        to return a new handler that performs whatever it requires
        and then calls the next handler.

        A simple example for a controller wrapper is a simple logging wrapper::

            def controller_wrapper(app_config, caller):
                def call(*args, **kw):
                    try:
                        print 'Before handler!'
                        return caller(*args, **kw)
                    finally:
                        print 'After Handler!'
                return call

            tg.hooks.wrap_controller(controller_wrapper)

        It is also possible to register wrappers for a specific controller::

            tg.hooks.wrap_controller(controller_wrapper, controller=RootController.index)

        """
        if environment_loaded.reached:
            raise TGConfigError(
                'Controller wrappers can be registered only at '
                'configuration time.')

        if controller is None:
            environment_loaded.register(
                _ApplicationHookRegistration('controller_wrapper', func))
        else:
            controller = default_im_func(controller)
            registration = _ControllerHookRegistration(controller,
                                                       'controller_wrapper',
                                                       func)
            renderers_ready.register(registration)
Beispiel #14
0
    def notify(self,
               hook_name,
               args=None,
               kwargs=None,
               controller=None,
               context_config=None):
        """Notifies a TurboGears hook.

        Each function registered for the given hook will be executed,
        ``args`` and ``kwargs`` will be passed to the registered functions
        as arguments.

        It permits to notify both application hooks::

            tg.hooks.notify('custom_global_hook')

        Or controller hooks::

            tg.hooks.notify('before_render', args=(remainder, params, output),
                            controller=RootController.index)

        """
        if context_config is None:  #pragma: no cover
            context_config = tg.config._current_obj()

        args = args or []
        kwargs = kwargs or {}

        try:
            syswide_hooks = context_config['hooks'][hook_name]
        except KeyError:  # pragma: no cover
            pass
        else:
            for func in syswide_hooks:
                func(*args, **kwargs)

        if controller is not None:
            controller = default_im_func(controller)
            deco = Decoration.get_decoration(controller)
            for func in deco.hooks.get(hook_name, []):
                func(*args, **kwargs)
Beispiel #15
0
    def wrap_controller(self, func, controller=None):
        """Registers a TurboGears controller wrapper.

        Controller Wrappers are much like a **decorator** applied to
        every controller.
        They receive :class:`tg.configuration.AppConfig` instance
        as an argument and the next handler in chain and are expected
        to return a new handler that performs whatever it requires
        and then calls the next handler.

        A simple example for a controller wrapper is a simple logging wrapper::

            def controller_wrapper(app_config, caller):
                def call(*args, **kw):
                    try:
                        print 'Before handler!'
                        return caller(*args, **kw)
                    finally:
                        print 'After Handler!'
                return call

            tg.hooks.wrap_controller(controller_wrapper)

        It is also possible to register wrappers for a specific controller::

            tg.hooks.wrap_controller(controller_wrapper, controller=RootController.index)

        """
        if config_ready.reached:
            raise TGConfigError('Controller wrappers can be registered only at '
                                'configuration time.')

        if controller is None:
            config_ready.register(_ApplicationHookRegistration('controller_wrapper', func))
        else:
            controller = default_im_func(controller)
            registration = _ControllerHookRegistration(controller, 'controller_wrapper', func)
            config_ready.register(registration)
Beispiel #16
0
    def _call(self, controller, params, remainder=None, context=None):
        """Run the controller with the given parameters.

        _call is called by _perform_call in CoreDispatcher.

        Any of the before_validate hook, the validation, the before_call hook,
        and the controller method can return a FormEncode Invalid exception,
        which will give the validation error handler the opportunity to provide
        a replacement decorated controller method and output that will
        subsequently be rendered.

        This allows for validation to display the original page or an
        abbreviated form with validation errors shown on validation failure.

        The before_render hook provides a place for functions that are called
        before the template is rendered. For example, you could use it to
        add and remove from the dictionary returned by the controller method,
        before it is passed to rendering.

        The after_render hook can act upon and modify the response out of
        rendering.

        """
        if context is None:  #pragma: no cover
            #compatibility with old code that didn't pass request locals explicitly
            context = tg.request.environ['tg.locals']

        context_config = tg.config._current_obj()
        self._initialize_validation_context(context)

        #This is necessary to prevent spurious Content Type header which would
        #cause problems to paste.response.replace_header calls and cause
        #responses wihout content type to get out with a wrong content type
        resp_headers = context.response.headers
        if not resp_headers.get('Content-Type'):
            resp_headers.pop('Content-Type', None)

        if remainder:
            remainder = tuple(map(url2pathname, remainder or []))
        else:
            remainder = tuple()

        hooks.notify('before_validate',
                     args=(remainder, params),
                     controller=controller,
                     context_config=context_config)

        try:
            validate_params = get_params_with_argspec(controller, params,
                                                      remainder)

            # Validate user input
            params = self._perform_validate(controller, validate_params)
            context.request.validation['values'] = params

            params, remainder = remove_argspec_params_from_params(
                controller, params, remainder)
            bound_controller_callable = controller
        except validation_errors as inv:
            instance, controller = self._process_validation_errors(
                controller, remainder, params, inv, context=context)
            bound_controller_callable = partial(controller, instance)

        hooks.notify('before_call',
                     args=(remainder, params),
                     controller=controller,
                     context_config=context_config)

        #apply controller wrappers
        try:
            default_controller_caller = context_config['controller_caller']
        except KeyError:
            default_controller_caller = call_controller

        try:
            dedicated_controller_wrappers = context_config[
                'dedicated_controller_wrappers']
            controller_caller = dedicated_controller_wrappers.get(
                default_im_func(controller), default_controller_caller)
        except KeyError:
            controller_caller = default_controller_caller

        # call controller method
        output = controller_caller(bound_controller_callable, remainder,
                                   params)

        # Render template
        hooks.notify('before_render',
                     args=(remainder, params, output),
                     controller=controller,
                     context_config=context_config)

        response = self._render_response(context, controller, output)

        hooks.notify('after_render',
                     args=(response, ),
                     controller=controller,
                     context_config=context_config)

        return response['response']
Beispiel #17
0
    def _call(self, controller, params, remainder=None, tgl=None):
        """Run the controller with the given parameters.

        _call is called by _perform_call in CoreDispatcher.

        Any of the before_validate hook, the validation, the before_call hook,
        and the controller method can return a FormEncode Invalid exception,
        which will give the validation error handler the opportunity to provide
        a replacement decorated controller method and output that will
        subsequently be rendered.

        This allows for validation to display the original page or an
        abbreviated form with validation errors shown on validation failure.

        The before_render hook provides a place for functions that are called
        before the template is rendered. For example, you could use it to
        add and remove from the dictionary returned by the controller method,
        before it is passed to rendering.

        The after_render hook can act upon and modify the response out of
        rendering.

        """
        if tgl is None: #pragma: no cover
            #compatibility with old code that didn't pass request locals explicitly
            tgl = tg.request.environ['tg.locals']

        context_config = tg.config._current_obj()
        self._initialize_validation_context(tgl)

        #This is necessary to prevent spurious Content Type header which would
        #cause problems to paste.response.replace_header calls and cause
        #responses wihout content type to get out with a wrong content type
        resp_headers = tgl.response.headers
        if not resp_headers.get('Content-Type'):
            resp_headers.pop('Content-Type', None)

        if remainder:
            remainder = tuple(map(url2pathname, remainder or []))
        else:
            remainder = tuple()

        try:
            hooks.notify('before_validate', args=(remainder, params),
                         controller=controller, context_config=context_config)

            validate_params = get_params_with_argspec(controller, params, remainder)

            # Validate user input
            params = self._perform_validate(controller, validate_params)

            tgl.request.validation['values'] = params

            hooks.notify('before_call', args=(remainder, params),
                         controller=controller, context_config=context_config)

            params, remainder = remove_argspec_params_from_params(controller, params, remainder)

            #apply controller wrappers
            try:
                default_controller_caller = context_config['controller_caller']
                dedicated_controller_wrappers = context_config['dedicated_controller_wrappers']
                controller_caller = dedicated_controller_wrappers.get(default_im_func(controller),
                                                                      default_controller_caller)
            except KeyError:
                controller_caller = call_controller

            # call controller method
            output = controller_caller(controller, remainder, params)

        except validation_errors as inv:
            controller, output = self._handle_validation_errors(controller, remainder, params,
                                                                inv, tgl=tgl)

        # Render template
        hooks.notify('before_render', args=(remainder, params, output),
                     controller=controller, context_config=context_config)

        response = self._render_response(tgl, controller, output)

        hooks.notify('after_render', args=(response,),
                     controller=controller, context_config=context_config)

        return response['response']