# -*- coding: utf-8 -*- """ flask.module ~~~~~~~~~~~~ Implements a class that represents module blueprints. :copyright: (c) 2010 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ from flask.helpers import _PackageBoundObject class _ModuleSetupState(object): def __init__(self, app, url_prefix=None): self.app = app self.url_prefix = url_prefix class Module(_PackageBoundObject): """Container object that enables pluggable applications. A module can be used to organize larger applications. They represent blueprints that, in combination with a :class:`Flask` object are used to create a large application. A module is like an application bound to an `import_name`. Multiple modules can share the same import names, but in that case a `name` has to be provided to keep them apart. If different import names are used, the rightmost part of the import name is used as name. Here an example structure for a larger appliation:: /myapplication /__init__.py /views /__init__.py /admin.py /frontend.py The `myapplication/__init__.py` can look like this:: from flask import Flask from myapplication.views.admin import admin from myapplication.views.frontend import frontend app = Flask(__name__) app.register_module(admin, url_prefix='/admin') app.register_module(frontend) And here an example view module (`myapplication/views/admin.py`):: from flask import Module admin = Module(__name__) @admin.route('/') def index(): pass @admin.route('/login') def login(): pass For a gentle introduction into modules, checkout the :ref:`working-with-modules` section. """ def __init__(self, import_name, name=None, url_prefix=None): if name is None: assert '.' in import_name, 'name required if package name ' \ 'does not point to a submodule' name = import_name.rsplit('.', 1)[1] _PackageBoundObject.__init__(self, import_name) self.name = name self.url_prefix = url_prefix self._register_events = [] def route(self, rule, **options): """Like :meth:`Flask.route` but for a module. The endpoint for the :func:`url_for` function is prefixed with the name of the module. """ def decorator(f): self.add_url_rule(rule, f.__name__, f, **options) return f return decorator def add_url_rule(self, rule, endpoint, view_func=None, **options): """Like :meth:`Flask.add_url_rule` but for a module. The endpoint for the :func:`url_for` function is prefixed with the name of the module. """ def register_rule(state): the_rule = rule if state.url_prefix: the_rule = state.url_prefix + rule state.app.add_url_rule(the_rule, '%s.%s' % (self.name, endpoint), view_func, **options) self._record(register_rule) def before_request(self, f): """Like :meth:`Flask.before_request` but for a module. This function is only executed before each request that is handled by a function of that module. """ self._record(lambda s: s.app.before_request_funcs .setdefault(self.name, []).append(f)) return f def before_app_request(self, f): """Like :meth:`Flask.before_request`. Such a function is executed before each request, even if outside of a module. """ self._record(lambda s: s.app.before_request_funcs .setdefault(None, []).append(f)) return f def after_request(self, f): """Like :meth:`Flask.after_request` but for a module. This function is only executed after each request that is handled by a function of that module. """ self._record(lambda s: s.app.after_request_funcs .setdefault(self.name, []).append(f)) return f def after_app_request(self, f): """Like :meth:`Flask.after_request` but for a module. Such a function is executed after each request, even if outside of the module. """ self._record(lambda s: s.app.after_request_funcs .setdefault(None, []).append(f)) return f def context_processor(self, f): """Like :meth:`Flask.context_processor` but for a module. This function is only executed for requests handled by a module. """ self._record(lambda s: s.app.template_context_processors .setdefault(self.name, []).append(f)) return f def app_context_processor(self, f): """Like :meth:`Flask.context_processor` but for a module. Such a function is executed each request, even if outside of the module. """ self._record(lambda s: s.app.template_context_processors .setdefault(None, []).append(f)) return f def app_errorhandler(self, code): """Like :meth:`Flask.errorhandler` but for a module. This handler is used for all requests, even if outside of the module. .. versionadded:: 0.4 """ def decorator(f): self._record(lambda s: s.app.errorhandler(code)(f)) return f return decorator def _record(self, func): self._register_events.append(func)