Browse Source

rewrite extension docs

remove old extension patterns
remove flask.ext from api docs
pull/2647/head
David Lord 7 years ago
parent
commit
4462cc57c8
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
  1. 16
      docs/api.rst
  2. 82
      docs/extensiondev.rst
  3. 71
      docs/extensions.rst

16
docs/api.rst

@ -370,22 +370,6 @@ Configuration
.. autoclass:: Config .. autoclass:: Config
:members: :members:
Extensions
----------
.. data:: flask.ext
This module acts as redirect import module to Flask extensions. It was
added in 0.8 as the canonical way to import Flask extensions and makes
it possible for us to have more flexibility in how we distribute
extensions.
If you want to use an extension named “Flask-Foo” you would import it
from :data:`~flask.ext` as follows::
from flask.ext import foo
.. versionadded:: 0.8
Stream Helpers Stream Helpers
-------------- --------------

82
docs/extensiondev.rst

@ -159,19 +159,10 @@ The Extension Code
Here's the contents of the `flask_sqlite3.py` for copy/paste:: Here's the contents of the `flask_sqlite3.py` for copy/paste::
import sqlite3 import sqlite3
from flask import current_app from flask import current_app, _app_ctx_stack
# Find the stack on which we want to store the database connection.
# Starting with Flask 0.9, the _app_ctx_stack is the correct one,
# before that we need to use the _request_ctx_stack.
try:
from flask import _app_ctx_stack as stack
except ImportError:
from flask import _request_ctx_stack as stack
class SQLite3(object): class SQLite3(object):
def __init__(self, app=None): def __init__(self, app=None):
self.app = app self.app = app
if app is not None: if app is not None:
@ -179,24 +170,19 @@ Here's the contents of the `flask_sqlite3.py` for copy/paste::
def init_app(self, app): def init_app(self, app):
app.config.setdefault('SQLITE3_DATABASE', ':memory:') app.config.setdefault('SQLITE3_DATABASE', ':memory:')
# Use the newstyle teardown_appcontext if it's available, app.teardown_appcontext(self.teardown)
# otherwise fall back to the request context
if hasattr(app, 'teardown_appcontext'):
app.teardown_appcontext(self.teardown)
else:
app.teardown_request(self.teardown)
def connect(self): def connect(self):
return sqlite3.connect(current_app.config['SQLITE3_DATABASE']) return sqlite3.connect(current_app.config['SQLITE3_DATABASE'])
def teardown(self, exception): def teardown(self, exception):
ctx = stack.top ctx = _app_ctx_stack.top
if hasattr(ctx, 'sqlite3_db'): if hasattr(ctx, 'sqlite3_db'):
ctx.sqlite3_db.close() ctx.sqlite3_db.close()
@property @property
def connection(self): def connection(self):
ctx = stack.top ctx = _app_ctx_stack.top
if ctx is not None: if ctx is not None:
if not hasattr(ctx, 'sqlite3_db'): if not hasattr(ctx, 'sqlite3_db'):
ctx.sqlite3_db = self.connect() ctx.sqlite3_db = self.connect()
@ -212,9 +198,7 @@ So here's what these lines of code do:
factory pattern for creating applications. The ``init_app`` will set the factory pattern for creating applications. The ``init_app`` will set the
configuration for the database, defaulting to an in memory database if configuration for the database, defaulting to an in memory database if
no configuration is supplied. In addition, the ``init_app`` method attaches no configuration is supplied. In addition, the ``init_app`` method attaches
the ``teardown`` handler. It will try to use the newstyle app context the ``teardown`` handler.
handler and if it does not exist, falls back to the request context
one.
3. Next, we define a ``connect`` method that opens a database connection. 3. Next, we define a ``connect`` method that opens a database connection.
4. Finally, we add a ``connection`` property that on first access opens 4. Finally, we add a ``connection`` property that on first access opens
the database connection and stores it on the context. This is also the database connection and stores it on the context. This is also
@ -224,9 +208,7 @@ So here's what these lines of code do:
Note here that we're attaching our database connection to the top Note here that we're attaching our database connection to the top
application context via ``_app_ctx_stack.top``. Extensions should use application context via ``_app_ctx_stack.top``. Extensions should use
the top context for storing their own information with a sufficiently the top context for storing their own information with a sufficiently
complex name. Note that we're falling back to the complex name.
``_request_ctx_stack.top`` if the application is using an older
version of Flask that does not support it.
So why did we decide on a class-based approach here? Because using our So why did we decide on a class-based approach here? Because using our
extension looks something like this:: extension looks something like this::
@ -245,9 +227,8 @@ You can then use the database from views like this::
cur = db.connection.cursor() cur = db.connection.cursor()
cur.execute(...) cur.execute(...)
Likewise if you are outside of a request but you are using Flask 0.9 or Likewise if you are outside of a request you can use the database by
later with the app context support, you can use the database in the same pushing an app context::
way::
with app.app_context(): with app.app_context():
cur = db.connection.cursor() cur = db.connection.cursor()
@ -291,34 +272,6 @@ teardown of a request, the ``sqlite3_db`` connection is closed. By using
this pattern, the *same* connection to the sqlite3 database is accessible this pattern, the *same* connection to the sqlite3 database is accessible
to anything that needs it for the duration of the request. to anything that needs it for the duration of the request.
If the :data:`~flask._app_ctx_stack` does not exist because the user uses
an old version of Flask, it is recommended to fall back to
:data:`~flask._request_ctx_stack` which is bound to a request.
Teardown Behavior
-----------------
*This is only relevant if you want to support Flask 0.6 and older*
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 Learn from Others
----------------- -----------------
@ -386,25 +339,6 @@ extension to be approved you have to follow these guidelines:
10. An extension currently has to support Python 3.4 and newer and 2.7. 10. An extension currently has to support Python 3.4 and newer and 2.7.
Extension Import Transition
---------------------------
In early versions of Flask we recommended using namespace packages for Flask
extensions, of the form ``flaskext.foo``. This turned out to be problematic in
practice because it meant that multiple ``flaskext`` packages coexist.
Consequently we have recommended to name extensions ``flask_foo`` over
``flaskext.foo`` for a long time.
Flask 0.8 introduced a redirect import system as a compatibility aid for app
developers: Importing ``flask.ext.foo`` would try ``flask_foo`` and
``flaskext.foo`` in that order.
As of Flask 0.11, most Flask extensions have transitioned to the new naming
schema. The ``flask.ext.foo`` compatibility alias is still in Flask 0.11 but is
now deprecated -- you should use ``flask_foo``.
.. _OAuth extension: https://pythonhosted.org/Flask-OAuth/ .. _OAuth extension: https://pythonhosted.org/Flask-OAuth/
.. _mailinglist: http://flask.pocoo.org/mailinglist/ .. _mailinglist: http://flask.pocoo.org/mailinglist/
.. _IRC channel: http://flask.pocoo.org/community/irc/ .. _IRC channel: http://flask.pocoo.org/community/irc/

71
docs/extensions.rst

@ -1,58 +1,53 @@
.. _extensions: .. _extensions:
Flask Extensions Extensions
================ ==========
Extensions are extra packages that add functionality to a Flask
application. For example, an extension might add support for sending
email or connecting to a database. Some extensions add entire new
frameworks to help build certain types of applications, like a ReST API.
Flask extensions extend the functionality of Flask in various different
ways. For instance they add support for databases and other common tasks.
Finding Extensions Finding Extensions
------------------ ------------------
Flask extensions are listed on the `Flask Extension Registry`_ and can be Flask extensions are usually named "Flask-Foo" or "Foo-Flask". Many
downloaded with :command:`easy_install` or :command:`pip`. If you add a Flask extension extensions are listed in the `Extension Registry`_, which can be updated
as dependency to your :file:`requirements.txt` or :file:`setup.py` file they are by extension developers. You can also search PyPI for packages tagged
usually installed with a simple command or when your application installs. with `Framework :: Flask <pypi_>`_.
Using Extensions Using Extensions
---------------- ----------------
Extensions typically have documentation that goes along that shows how to Consult each extension's documentation for installation, configuration,
use it. There are no general rules in how extensions are supposed to and usage instructions. Generally, extensions pull their own
behave but they are imported from common locations. If you have an configuration from :attr:`app.config <flask.Flask.config>` and are
extension called ``Flask-Foo`` or ``Foo-Flask`` it should be always passed an application instance during initialization. For example,
importable from ``flask_foo``:: an extension caled "Flask-Foo" might be used like this::
import flask_foo from flask_foo import Foo
Building Extensions foo = Foo()
-------------------
While `Flask Extension Registry`_ contains many Flask extensions, you may not find app = Flask(__name__)
an extension that fits your need. If this is the case, you can always create your own. app.config.update(
Consider reading :ref:`extension-dev` to develop your own Flask extension. FOO_BAR='baz',
FOO_SPAM='eggs',
)
Flask Before 0.8 foo.init_app(app)
----------------
If you are using Flask 0.7 or earlier the :data:`flask.ext` package will not
exist, instead you have to import from ``flaskext.foo`` or ``flask_foo``
depending on how the extension is distributed. If you want to develop an
application that supports Flask 0.7 or earlier you should still import
from the :data:`flask.ext` package. We provide you with a compatibility
module that provides this package for older versions of Flask. You can
download it from GitHub: `flaskext_compat.py`_
And here is how you can use it:: Building Extensions
-------------------
import flaskext_compat
flaskext_compat.activate()
from flask.ext import foo
Once the ``flaskext_compat`` module is activated the :data:`flask.ext` will While the `Extension Registry`_ contains many Flask extensions, you may
exist and you can start importing from there. not find an extension that fits your need. If this is the case, you can
create your own. Read :ref:`extension-dev` to develop your own Flask
extension.
.. _Flask Extension Registry: http://flask.pocoo.org/extensions/ .. _Extension Registry: http://flask.pocoo.org/extensions/
.. _flaskext_compat.py: https://raw.githubusercontent.com/pallets/flask/master/scripts/flaskext_compat.py .. _pypi: https://pypi.python.org/pypi?:action=browse&c=585

Loading…
Cancel
Save