Flask Extension Development
If you want to create your own Flask extension for something that does notexist yet, this guide to extension development will help you get yourextension running in no time and to feel like users would expect yourextension to behave.
Extensions are all located in a package called where “something” is the name of the library you want to bridge. So forexample if you plan to add support for a library named _simplexml toFlask, you would name your extension’s package flask_simplexml
.
The name of the actual extension (the human readable name) however wouldbe 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 intheir setup.py
files.
But what do extensions look like themselves? An extension has to ensurethat it works with multiple Flask application instances at once. This isa requirement because many people will use patterns like theApplication Factories pattern to create their application as needed to aidunittests and to support multiple configurations. Because of that it iscrucial that your application supports that kind of behavior.
Most importantly the extension must be shipped with a setup.py
file andregistered on PyPI. Also the development checkout link should work sothat people can easily install the development version into theirvirtualenv without having to download the library by hand.
Flask extensions must be licensed under a BSD, MIT or more liberal licensein order to be listed in the Flask Extension Registry. Keep in mindthat the Flask Extension Registry is a moderated place and libraries willbe reviewed upfront if they behave as required.
“Hello Flaskext!”
So let’s get started with creating such a Flask extension. The extensionwe want to create here will provide very basic support for SQLite3.
First we create the following folder structure:
Here’s the contents of the most important files:
The next file that is absolutely required is the setup.py
file which isused to install your Flask extension. The following contents aresomething 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_email='[email protected]',
- 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 existingextensions and adapt.
flask_sqlite3.py
Now this is where your extension code goes. But how exactly should suchan extension look like? What are the best practices? Continue readingfor some insight.
Many extensions will need some kind of initialization step. For example,consider an application that’s currently connecting to SQLite like thedocumentation suggests (Using SQLite 3 with Flask). So how does the extensionknow 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:
classes:
What to use depends on what you have in mind. For the SQLite 3 extensionwe will use the class-based approach because it will provide users with anobject that handles opening and closing database connections.
When designing your classes, it’s important to make them easily reusableat the module level. This means the object itself must not under anycircumstances store any application specific state and must be shareablebetween different applications.
The Extension Code
Here’s the contents of the flask_sqlite3.py for copy/paste:
So here’s what these lines of code do:
The
init_app
method exists so that theSQLite3
object can beinstantiated without requiring an app object. This method supports thefactory pattern for creating applications. Theinit_app
will set theconfiguration for the database, defaulting to an in memory database ifno configuration is supplied. In addition, theinit_app
methodattaches theteardown
handler.Next, we define a method that opens a database connection.
Finally, we add a
connection
property that on first access opensthe database connection and stores it on the context. This is alsothe recommended way to handling resources: fetch resources lazily thefirst time they are used.
Note here that we’re attaching our database connection to the topapplication context via _app_ctx_stack.top
. Extensions should usethe top context for storing their own information with a sufficientlycomplex name.
So why did we decide on a class-based approach here? Because using ourextension looks something like this:
- from flask import Flask
- from flask_sqlite3 import SQLite3
- app = Flask(__name__)
- app.config.from_pyfile('the-config.cfg')
- db = SQLite3(app)
You can then use the database from views like this:
Likewise if you are outside of a request you can use the database bypushing an app context:
- with app.app_context():
- cur = db.connection.cursor()
- cur.execute(...)
At the end of the with
block the teardown handles will be executedautomatically.
Additionally, the init_app
method is used to support the factory patternfor creating apps:
Keep in mind that supporting this factory pattern for creating apps is requiredfor approved flask extensions (described below).
Note on init_app
When the extension needs to find the current application and it doesnot have a reference to it, it must either use thecurrent_app
context local or change the API in a waythat you can pass the application explicitly.
In the example above, before every request, a sqlite3db
variable isassigned to _app_ctx_stack.top
. In a view function, this variable isaccessible using the connection
property of . During theteardown of a request, the sqlite3_db
connection is closed. By usingthis pattern, the _same connection to the sqlite3 database is accessibleto anything that needs it for the duration of the request.
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 extensionson the PyPI. If you feel lost there is still the and theIRC channel to get some ideas for nice looking APIs. Especially if you dosomething nobody before you did, it might be a very good idea to get some moreinput. This not only generates useful feedback on what people might want froman extension, but also avoids having multiple developers working in isolationon pretty much the same problem.
Remember: good API design is hard, so introduce your project on themailing list, and let other developers give you a helping hand withdesigning the API.
The best Flask extensions are extensions that share common idioms for theAPI. And this can only work if collaboration happens early.
Flask also has the concept of approved extensions. Approved extensionsare tested as part of Flask itself to ensure extensions do not break onnew releases. If you want your own extension to be approved you have tofollow these guidelines:
An approved Flask extension requires a maintainer. In the event anextension author would like to move beyond the project, the project shouldfind a new maintainer including full source hosting transition and PyPIaccess. If no maintainer is available, give access to the Flask core team.
An approved Flask extension must provide exactly one package or modulenamed
flask_extensionname
.It must ship a testing suite that can either be invoked with
make test
orpython setup.py test
. For test suites invoked withmaketest
the extension has to ensure that all dependencies for the testare installed automatically. If tests are invoked withpython setup.pytest
, test dependencies can be specified in thesetup.py
file.The test suite also has to be part of the distribution.APIs of approved extensions will be checked for the followingcharacteristics:
The license must be BSD/MIT/WTFPL licensed.
The naming scheme for official extensions is Flask-ExtensionName orExtensionName-Flask.
Approved extensions must define all their dependencies in the
setup.py
file unless a dependency cannot be met because it is notavailable on PyPI.The documentation must use the
flask
theme from the.The setup.py description (and thus the PyPI description) has tolink to the documentation, website (if there is one) and theremust be a link to automatically install the development version(
PackageName==dev
).