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)
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})
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})
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))
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))
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
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
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
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
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
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)
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)
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)
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)
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']
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']