diff options
Diffstat (limited to 'app/static/doc/flask-docs/_sources/extensiondev.txt')
-rw-r--r-- | app/static/doc/flask-docs/_sources/extensiondev.txt | 387 |
1 files changed, 0 insertions, 387 deletions
diff --git a/app/static/doc/flask-docs/_sources/extensiondev.txt b/app/static/doc/flask-docs/_sources/extensiondev.txt deleted file mode 100644 index ee0d5e6..0000000 --- a/app/static/doc/flask-docs/_sources/extensiondev.txt +++ /dev/null @@ -1,387 +0,0 @@ -Flask Extension Development -=========================== - -Flask, being a microframework, often requires some repetitive steps to get -a third party library working. Because very often these steps could be -abstracted to support multiple projects the `Flask Extension Registry`_ -was created. - -If you want to create your own Flask extension for something that does not -exist yet, this guide to extension development will help you get your -extension running in no time and to feel like users would expect your -extension to behave. - -.. _Flask Extension Registry: http://flask.pocoo.org/extensions/ - -Anatomy of an Extension ------------------------ - -Extensions are all located in a package called ``flask_something`` -where "something" is the name of the library you want to bridge. So for -example if you plan to add support for a library named `simplexml` to -Flask, you would name your extension's package ``flask_simplexml``. - -The name of the actual extension (the human readable name) however would -be something like "Flask-SimpleXML". Make sure to include the name -"Flask" somewhere in that name and that you check the capitalization. -This is how users can then register dependencies to your extension in -their `setup.py` files. - -Flask sets up a redirect package called :data:`flask.ext` where users -should import the extensions from. If you for instance have a package -called ``flask_something`` users would import it as -``flask.ext.something``. This is done to transition from the old -namespace packages. See :ref:`ext-import-transition` for more details. - -But how do extensions look like themselves? An extension has to ensure -that it works with multiple Flask application instances at once. This is -a requirement because many people will use patterns like the -:ref:`app-factories` pattern to create their application as needed to aid -unittests and to support multiple configurations. Because of that it is -crucial that your application supports that kind of behaviour. - -Most importantly the extension must be shipped with a `setup.py` file and -registered on PyPI. Also the development checkout link should work so -that people can easily install the development version into their -virtualenv without having to download the library by hand. - -Flask extensions must be licensed as BSD or MIT or a more liberal license -to be enlisted on the Flask Extension Registry. Keep in mind that the -Flask Extension Registry is a moderated place and libraries will be -reviewed upfront if they behave as required. - -"Hello Flaskext!" ------------------ - -So let's get started with creating such a Flask extension. The extension -we want to create here will provide very basic support for SQLite3. - -First we create the following folder structure:: - - flask-sqlite3/ - flask_sqlite3.py - LICENSE - README - -Here's the contents of the most important files: - -setup.py -```````` - -The next file that is absolutely required is the `setup.py` file which is -used to install your Flask extension. The following contents are -something you can work with:: - - """ - Flask-SQLite3 - ------------- - - This is the description for that library - """ - from setuptools import setup - - - setup( - name='Flask-SQLite3', - version='1.0', - url='http://example.com/flask-sqlite3/', - license='BSD', - author='Your Name', - author_email='your-email@example.com', - description='Very short description', - long_description=__doc__, - py_modules=['flask_sqlite3'], - # if you would be using a package instead use packages instead - # of py_modules: - # packages=['flask_sqlite3'], - zip_safe=False, - include_package_data=True, - platforms='any', - install_requires=[ - 'Flask' - ], - classifiers=[ - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - 'Topic :: Software Development :: Libraries :: Python Modules' - ] - ) - -That's a lot of code but you can really just copy/paste that from existing -extensions and adapt. - -flask_sqlite3.py -```````````````` - -Now this is where your extension code goes. But how exactly should such -an extension look like? What are the best practices? Continue reading -for some insight. - -Initializing Extensions ------------------------ - -Many extensions will need some kind of initialization step. For example, -consider your application is currently connecting to SQLite like the -documentation suggests (:ref:`sqlite3`) you will need to provide a few -functions and before / after request handlers. So how does the extension -know the name of the application object? - -Quite simple: you pass it to it. - -There are two recommended ways for an extension to initialize: - -initialization functions: - If your extension is called `helloworld` you might have a function - called ``init_helloworld(app[, extra_args])`` that initializes the - extension for that application. It could attach before / after - handlers etc. - -classes: - Classes work mostly like initialization functions but can later be - used to further change the behaviour. For an example look at how the - `OAuth extension`_ works: there is an `OAuth` object that provides - some helper functions like `OAuth.remote_app` to create a reference to - a remote application that uses OAuth. - -What to use depends on what you have in mind. For the SQLite 3 extension -we will use the class based approach because it will provide users with a -manager object that handles opening and closing database connections. - -The Extension Code ------------------- - -Here's the contents of the `flask_sqlite3.py` for copy/paste:: - - from __future__ import absolute_import - import sqlite3 - - from flask import _request_ctx_stack - - class SQLite3(object): - - def __init__(self, app): - self.app = app - self.app.config.setdefault('SQLITE3_DATABASE', ':memory:') - self.app.teardown_request(self.teardown_request) - self.app.before_request(self.before_request) - - def connect(self): - return sqlite3.connect(self.app.config['SQLITE3_DATABASE']) - - def before_request(self): - ctx = _request_ctx_stack.top - ctx.sqlite3_db = self.connect() - - def teardown_request(self, exception): - ctx = _request_ctx_stack.top - ctx.sqlite3_db.close() - - def get_db(self): - ctx = _request_ctx_stack.top - if ctx is not None: - return ctx.sqlite3_db - -So here's what these lines of code do: - -1. The ``__future__`` import is necessary to activate absolute imports. - Otherwise we could not call our module `sqlite3.py` and import the - top-level `sqlite3` module which actually implements the connection to - SQLite. -2. We create a class for our extension that requires a supplied `app` object, - sets a configuration for the database if it's not there - (:meth:`dict.setdefault`), and attaches `before_request` and - `teardown_request` handlers. -3. Next, we define a `connect` function that opens a database connection. -4. Then we set up the request handlers we bound to the app above. Note here - that we're attaching our database connection to the top request context via - `_request_ctx_stack.top`. Extensions should use the top context and not the - `g` object to store things like database connections. -5. Finally, we add a `get_db` function that simplifies access to the context's - database. - -So why did we decide on a class based approach here? Because using our -extension looks something like this:: - - from flask import Flask - from flask_sqlite3 import SQLite3 - - app = Flask(__name__) - app.config.from_pyfile('the-config.cfg') - manager = SQLite3(app) - db = manager.get_db() - -You can then use the database from views like this:: - - @app.route('/') - def show_all(): - cur = db.cursor() - cur.execute(...) - -Opening a database connection from outside a view function is simple. - ->>> from yourapplication import db ->>> cur = db.cursor() ->>> cur.execute(...) - -Adding an `init_app` Function ------------------------------ - -In practice, you'll almost always want to permit users to initialize your -extension and provide an app object after the fact. This can help avoid -circular import problems when a user is breaking their app into multiple files. -Our extension could add an `init_app` function as follows:: - - class SQLite3(object): - - def __init__(self, app=None): - if app is not None: - self.app = app - self.init_app(self.app) - else: - self.app = None - - def init_app(self, app): - self.app = app - self.app.config.setdefault('SQLITE3_DATABASE', ':memory:') - self.app.teardown_request(self.teardown_request) - self.app.before_request(self.before_request) - - def connect(self): - return sqlite3.connect(app.config['SQLITE3_DATABASE']) - - def before_request(self): - ctx = _request_ctx_stack.top - ctx.sqlite3_db = self.connect() - - def teardown_request(self, exception): - ctx = _request_ctx_stack.top - ctx.sqlite3_db.close() - - def get_db(self): - ctx = _request_ctx_stack.top - if ctx is not None: - return ctx.sqlite3_db - -The user could then initialize the extension in one file:: - - manager = SQLite3() - -and bind their app to the extension in another file:: - - manager.init_app(app) - -End-Of-Request Behavior ------------------------ - -Due to the change in Flask 0.7 regarding functions that are run at the end -of the request your extension will have to be extra careful there if it -wants to continue to support older versions of Flask. The following -pattern is a good way to support both:: - - def close_connection(response): - ctx = _request_ctx_stack.top - ctx.sqlite3_db.close() - return response - - if hasattr(app, 'teardown_request'): - app.teardown_request(close_connection) - else: - app.after_request(close_connection) - -Strictly speaking the above code is wrong, because teardown functions are -passed the exception and typically don't return anything. However because -the return value is discarded this will just work assuming that the code -in between does not touch the passed parameter. - -Learn from Others ------------------ - -This documentation only touches the bare minimum for extension -development. If you want to learn more, it's a very good idea to check -out existing extensions on the `Flask Extension Registry`_. If you feel -lost there is still the `mailinglist`_ and the `IRC channel`_ to get some -ideas for nice looking APIs. Especially if you do something nobody before -you did, it might be a very good idea to get some more input. This not -only to get an idea about what people might want to have from an -extension, but also to avoid having multiple developers working on pretty -much the same side by side. - -Remember: good API design is hard, so introduce your project on the -mailinglist, and let other developers give you a helping hand with -designing the API. - -The best Flask extensions are extensions that share common idioms for the -API. And this can only work if collaboration happens early. - -Approved Extensions -------------------- - -Flask also has the concept of approved extensions. Approved extensions -are tested as part of Flask itself to ensure extensions do not break on -new releases. These approved extensions are listed on the `Flask -Extension Registry`_ and marked appropriately. If you want your own -extension to be approved you have to follow these guidelines: - -1. An approved Flask extension must provide exactly one package or module - named ``flask_extensionname``. They might also reside inside a - ``flaskext`` namespace packages though this is discouraged now. -2. It must ship a testing suite that can either be invoked with ``make test`` - or ``python setup.py test``. For test suites invoked with ``make - test`` the extension has to ensure that all dependencies for the test - are installed automatically, in case of ``python setup.py test`` - dependencies for tests alone can be specified in the `setup.py` - file. The test suite also has to be part of the distribution. -3. APIs of approved extensions will be checked for the following - characteristics: - - - an approved extension has to support multiple applications - running in the same Python process. - - it must be possible to use the factory pattern for creating - applications. - -4. The license must be BSD/MIT/WTFPL licensed. -5. The naming scheme for official extensions is *Flask-ExtensionName* or - *ExtensionName-Flask*. -6. Approved extensions must define all their dependencies in the - `setup.py` file unless a dependency cannot be met because it is not - available on PyPI. -7. The extension must have documentation that uses one of the two Flask - themes for Sphinx documentation. -8. The setup.py description (and thus the PyPI description) has to - link to the documentation, website (if there is one) and there - must be a link to automatically install the development version - (``PackageName==dev``). -9. The ``zip_safe`` flag in the setup script must be set to ``False``, - even if the extension would be safe for zipping. -10. An extension currently has to support Python 2.5, 2.6 as well as - Python 2.7 - - -.. _ext-import-transition: - -Extension Import Transition ---------------------------- - -For a while we recommended using namespace packages for Flask extensions. -This turned out to be problematic in practice because many different -competing namespace package systems exist and pip would automatically -switch between different systems and this caused a lot of problems for -users. - -Instead we now recommend naming packages ``flask_foo`` instead of the now -deprecated ``flaskext.foo``. Flask 0.8 introduces a redirect import -system that lets uses import from ``flask.ext.foo`` and it will try -``flask_foo`` first and if that fails ``flaskext.foo``. - -Flask extensions should urge users to import from ``flask.ext.foo`` -instead of ``flask_foo`` or ``flaskext_foo`` so that extensions can -transition to the new package name without affecting users. - - -.. _OAuth extension: http://packages.python.org/Flask-OAuth/ -.. _mailinglist: http://flask.pocoo.org/mailinglist/ -.. _IRC channel: http://flask.pocoo.org/community/irc/ |