From 0719ad5f4fa7d52d38706b3ee60ef91dcfbaa98d Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 18 Sep 2011 13:03:05 +0200 Subject: [PATCH] Documented new import system for extensions --- docs/extensiondev.rst | 80 +++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/docs/extensiondev.rst b/docs/extensiondev.rst index 6b407b34..ee0d5e60 100644 --- a/docs/extensiondev.rst +++ b/docs/extensiondev.rst @@ -16,10 +16,10 @@ extension to behave. Anatomy of an Extension ----------------------- -Extensions are all located in a package called ``flaskext.something`` +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 ``flaskext.simplexml``. +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 @@ -27,9 +27,11 @@ be something like "Flask-SimpleXML". Make sure to include the name This is how users can then register dependencies to your extension in their `setup.py` files. -The magic that makes it possible to have your library in a package called -``flaskext.something`` is called a "namespace package". Check out the -guide below how to create something like that. +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 @@ -54,35 +56,15 @@ reviewed upfront if they behave as required. 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. -There is a script on github called `Flask Extension Wizard`_ which helps -you create the initial folder structure. But for this very basic example -we want to create all by hand to get a better feeling for it. - First we create the following folder structure:: flask-sqlite3/ - flaskext/ - __init__.py - sqlite3.py - setup.py + flask_sqlite3.py LICENSE + README Here's the contents of the most important files: -flaskext/__init__.py -```````````````````` - -The only purpose of this file is to mark the package as namespace package. -This is required so that multiple modules from different PyPI packages can -reside in the same Python package:: - - __import__('pkg_resources').declare_namespace(__name__) - -If you want to know exactly what is happening there, checkout the -distribute or setuptools docs which explain how this works. - -Just make sure to not put anything else in there! - setup.py ```````` @@ -108,9 +90,12 @@ something you can work with:: author_email='your-email@example.com', description='Very short description', long_description=__doc__, - packages=['flaskext'], - namespace_packages=['flaskext'], + 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' @@ -127,11 +112,10 @@ something you can work with:: ) That's a lot of code but you can really just copy/paste that from existing -extensions and adapt. This is also what the wizard creates for you if you -use it. +extensions and adapt. -flaskext/sqlite3.py -``````````````````` +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 @@ -170,7 +154,7 @@ manager object that handles opening and closing database connections. The Extension Code ------------------ -Here's the contents of the `flaskext/sqlite3.py` for copy/paste:: +Here's the contents of the `flask_sqlite3.py` for copy/paste:: from __future__ import absolute_import import sqlite3 @@ -223,7 +207,7 @@ So why did we decide on a class based approach here? Because using our extension looks something like this:: from flask import Flask - from flaskext.sqlite3 import SQLite3 + from flask_sqlite3 import SQLite3 app = Flask(__name__) app.config.from_pyfile('the-config.cfg') @@ -343,7 +327,8 @@ 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 - inside the `flaskext` namespace package. + 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 @@ -376,8 +361,27 @@ extension to be approved you have to follow these guidelines: Python 2.7 -.. _Flask Extension Wizard: - http://github.com/mitsuhiko/flask-extension-wizard +.. _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/