diff options
Diffstat (limited to 'studio/static/doc/flask-docs/extensiondev.html')
-rw-r--r-- | studio/static/doc/flask-docs/extensiondev.html | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/studio/static/doc/flask-docs/extensiondev.html b/studio/static/doc/flask-docs/extensiondev.html new file mode 100644 index 0000000..05044b0 --- /dev/null +++ b/studio/static/doc/flask-docs/extensiondev.html @@ -0,0 +1,475 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Flask Extension Development — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="_static/jquery.js"></script> + <script type="text/javascript" src="_static/underscore.js"></script> + <script type="text/javascript" src="_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="index.html" /> + <link rel="next" title="Pocoo Styleguide" href="styleguide.html" /> + <link rel="prev" title="Unicode in Flask" href="unicode.html" /> + + + <link rel="apple-touch-icon" href="_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="styleguide.html" title="Pocoo Styleguide" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="unicode.html" title="Unicode in Flask" + accesskey="P">previous</a> |</li> + <li><a href="index.html">Flask 0.8 documentation</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="flask-extension-development"> +<h1>Flask Extension Development<a class="headerlink" href="#flask-extension-development" title="Permalink to this headline">¶</a></h1> +<p>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 <a class="reference external" href="http://flask.pocoo.org/extensions/">Flask Extension Registry</a> +was created.</p> +<p>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.</p> +<div class="section" id="anatomy-of-an-extension"> +<h2>Anatomy of an Extension<a class="headerlink" href="#anatomy-of-an-extension" title="Permalink to this headline">¶</a></h2> +<p>Extensions are all located in a package called <tt class="docutils literal"><span class="pre">flask_something</span></tt> +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 <cite>simplexml</cite> to +Flask, you would name your extension’s package <tt class="docutils literal"><span class="pre">flask_simplexml</span></tt>.</p> +<p>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 <cite>setup.py</cite> files.</p> +<p>Flask sets up a redirect package called <tt class="xref py py-data docutils literal"><span class="pre">flask.ext</span></tt> where users +should import the extensions from. If you for instance have a package +called <tt class="docutils literal"><span class="pre">flask_something</span></tt> users would import it as +<tt class="docutils literal"><span class="pre">flask.ext.something</span></tt>. This is done to transition from the old +namespace packages. See <a class="reference internal" href="#ext-import-transition"><em>Extension Import Transition</em></a> for more details.</p> +<p>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 +<a class="reference internal" href="patterns/appfactories.html#app-factories"><em>Application Factories</em></a> 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.</p> +<p>Most importantly the extension must be shipped with a <cite>setup.py</cite> 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.</p> +<p>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.</p> +</div> +<div class="section" id="hello-flaskext"> +<h2>“Hello Flaskext!”<a class="headerlink" href="#hello-flaskext" title="Permalink to this headline">¶</a></h2> +<p>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.</p> +<p>First we create the following folder structure:</p> +<div class="highlight-python"><pre>flask-sqlite3/ + flask_sqlite3.py + LICENSE + README</pre> +</div> +<p>Here’s the contents of the most important files:</p> +<div class="section" id="setup-py"> +<h3>setup.py<a class="headerlink" href="#setup-py" title="Permalink to this headline">¶</a></h3> +<p>The next file that is absolutely required is the <cite>setup.py</cite> file which is +used to install your Flask extension. The following contents are +something you can work with:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="sd">"""</span> +<span class="sd">Flask-SQLite3</span> +<span class="sd">-------------</span> + +<span class="sd">This is the description for that library</span> +<span class="sd">"""</span> +<span class="kn">from</span> <span class="nn">setuptools</span> <span class="kn">import</span> <span class="n">setup</span> + + +<span class="n">setup</span><span class="p">(</span> + <span class="n">name</span><span class="o">=</span><span class="s">'Flask-SQLite3'</span><span class="p">,</span> + <span class="n">version</span><span class="o">=</span><span class="s">'1.0'</span><span class="p">,</span> + <span class="n">url</span><span class="o">=</span><span class="s">'http://example.com/flask-sqlite3/'</span><span class="p">,</span> + <span class="n">license</span><span class="o">=</span><span class="s">'BSD'</span><span class="p">,</span> + <span class="n">author</span><span class="o">=</span><span class="s">'Your Name'</span><span class="p">,</span> + <span class="n">author_email</span><span class="o">=</span><span class="s">'your-email@example.com'</span><span class="p">,</span> + <span class="n">description</span><span class="o">=</span><span class="s">'Very short description'</span><span class="p">,</span> + <span class="n">long_description</span><span class="o">=</span><span class="n">__doc__</span><span class="p">,</span> + <span class="n">py_modules</span><span class="o">=</span><span class="p">[</span><span class="s">'flask_sqlite3'</span><span class="p">],</span> + <span class="c"># if you would be using a package instead use packages instead</span> + <span class="c"># of py_modules:</span> + <span class="c"># packages=['flask_sqlite3'],</span> + <span class="n">zip_safe</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> + <span class="n">include_package_data</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> + <span class="n">platforms</span><span class="o">=</span><span class="s">'any'</span><span class="p">,</span> + <span class="n">install_requires</span><span class="o">=</span><span class="p">[</span> + <span class="s">'Flask'</span> + <span class="p">],</span> + <span class="n">classifiers</span><span class="o">=</span><span class="p">[</span> + <span class="s">'Environment :: Web Environment'</span><span class="p">,</span> + <span class="s">'Intended Audience :: Developers'</span><span class="p">,</span> + <span class="s">'License :: OSI Approved :: BSD License'</span><span class="p">,</span> + <span class="s">'Operating System :: OS Independent'</span><span class="p">,</span> + <span class="s">'Programming Language :: Python'</span><span class="p">,</span> + <span class="s">'Topic :: Internet :: WWW/HTTP :: Dynamic Content'</span><span class="p">,</span> + <span class="s">'Topic :: Software Development :: Libraries :: Python Modules'</span> + <span class="p">]</span> +<span class="p">)</span> +</pre></div> +</div> +<p>That’s a lot of code but you can really just copy/paste that from existing +extensions and adapt.</p> +</div> +<div class="section" id="flask-sqlite3-py"> +<h3>flask_sqlite3.py<a class="headerlink" href="#flask-sqlite3-py" title="Permalink to this headline">¶</a></h3> +<p>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.</p> +</div> +</div> +<div class="section" id="initializing-extensions"> +<h2>Initializing Extensions<a class="headerlink" href="#initializing-extensions" title="Permalink to this headline">¶</a></h2> +<p>Many extensions will need some kind of initialization step. For example, +consider your application is currently connecting to SQLite like the +documentation suggests (<a class="reference internal" href="patterns/sqlite3.html#sqlite3"><em>Using SQLite 3 with Flask</em></a>) 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?</p> +<p>Quite simple: you pass it to it.</p> +<p>There are two recommended ways for an extension to initialize:</p> +<dl class="docutils"> +<dt>initialization functions:</dt> +<dd>If your extension is called <cite>helloworld</cite> you might have a function +called <tt class="docutils literal"><span class="pre">init_helloworld(app[,</span> <span class="pre">extra_args])</span></tt> that initializes the +extension for that application. It could attach before / after +handlers etc.</dd> +<dt>classes:</dt> +<dd>Classes work mostly like initialization functions but can later be +used to further change the behaviour. For an example look at how the +<a class="reference external" href="http://packages.python.org/Flask-OAuth/">OAuth extension</a> works: there is an <cite>OAuth</cite> object that provides +some helper functions like <cite>OAuth.remote_app</cite> to create a reference to +a remote application that uses OAuth.</dd> +</dl> +<p>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.</p> +</div> +<div class="section" id="the-extension-code"> +<h2>The Extension Code<a class="headerlink" href="#the-extension-code" title="Permalink to this headline">¶</a></h2> +<p>Here’s the contents of the <cite>flask_sqlite3.py</cite> for copy/paste:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">absolute_import</span> +<span class="kn">import</span> <span class="nn">sqlite3</span> + +<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">_request_ctx_stack</span> + +<span class="k">class</span> <span class="nc">SQLite3</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> + + <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span> <span class="o">=</span> <span class="n">app</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s">'SQLITE3_DATABASE'</span><span class="p">,</span> <span class="s">':memory:'</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">teardown_request</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">teardown_request</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">before_request</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">before_request</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">return</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'SQLITE3_DATABASE'</span><span class="p">])</span> + + <span class="k">def</span> <span class="nf">before_request</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="n">_request_ctx_stack</span><span class="o">.</span><span class="n">top</span> + <span class="n">ctx</span><span class="o">.</span><span class="n">sqlite3_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> + + <span class="k">def</span> <span class="nf">teardown_request</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exception</span><span class="p">):</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="n">_request_ctx_stack</span><span class="o">.</span><span class="n">top</span> + <span class="n">ctx</span><span class="o">.</span><span class="n">sqlite3_db</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> + + <span class="k">def</span> <span class="nf">get_db</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="n">_request_ctx_stack</span><span class="o">.</span><span class="n">top</span> + <span class="k">if</span> <span class="n">ctx</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> + <span class="k">return</span> <span class="n">ctx</span><span class="o">.</span><span class="n">sqlite3_db</span> +</pre></div> +</div> +<p>So here’s what these lines of code do:</p> +<ol class="arabic simple"> +<li>The <tt class="docutils literal"><span class="pre">__future__</span></tt> import is necessary to activate absolute imports. +Otherwise we could not call our module <cite>sqlite3.py</cite> and import the +top-level <cite>sqlite3</cite> module which actually implements the connection to +SQLite.</li> +<li>We create a class for our extension that requires a supplied <cite>app</cite> object, +sets a configuration for the database if it’s not there +(<a class="reference external" href="http://docs.python.org/dev/library/stdtypes.html#dict.setdefault" title="(in Python v3.3)"><tt class="xref py py-meth docutils literal"><span class="pre">dict.setdefault()</span></tt></a>), and attaches <cite>before_request</cite> and +<cite>teardown_request</cite> handlers.</li> +<li>Next, we define a <cite>connect</cite> function that opens a database connection.</li> +<li>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 +<cite>_request_ctx_stack.top</cite>. Extensions should use the top context and not the +<cite>g</cite> object to store things like database connections.</li> +<li>Finally, we add a <cite>get_db</cite> function that simplifies access to the context’s +database.</li> +</ol> +<p>So why did we decide on a class based approach here? Because using our +extension looks something like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> +<span class="kn">from</span> <span class="nn">flask_sqlite3</span> <span class="kn">import</span> <span class="n">SQLite3</span> + +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_pyfile</span><span class="p">(</span><span class="s">'the-config.cfg'</span><span class="p">)</span> +<span class="n">manager</span> <span class="o">=</span> <span class="n">SQLite3</span><span class="p">(</span><span class="n">app</span><span class="p">)</span> +<span class="n">db</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="n">get_db</span><span class="p">()</span> +</pre></div> +</div> +<p>You can then use the database from views like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">show_all</span><span class="p">():</span> + <span class="n">cur</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> + <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> +</pre></div> +</div> +<p>Opening a database connection from outside a view function is simple.</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">yourapplication</span> <span class="kn">import</span> <span class="n">db</span> +<span class="gp">>>> </span><span class="n">cur</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> +</pre></div> +</div> +</div> +<div class="section" id="adding-an-init-app-function"> +<h2>Adding an <cite>init_app</cite> Function<a class="headerlink" href="#adding-an-init-app-function" title="Permalink to this headline">¶</a></h2> +<p>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 <cite>init_app</cite> function as follows:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">SQLite3</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> + + <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span> + <span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span> <span class="o">=</span> <span class="n">app</span> + <span class="bp">self</span><span class="o">.</span><span class="n">init_app</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span> <span class="o">=</span> <span class="bp">None</span> + + <span class="k">def</span> <span class="nf">init_app</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span> <span class="o">=</span> <span class="n">app</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s">'SQLITE3_DATABASE'</span><span class="p">,</span> <span class="s">':memory:'</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">teardown_request</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">teardown_request</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">before_request</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">before_request</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">return</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'SQLITE3_DATABASE'</span><span class="p">])</span> + + <span class="k">def</span> <span class="nf">before_request</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="n">_request_ctx_stack</span><span class="o">.</span><span class="n">top</span> + <span class="n">ctx</span><span class="o">.</span><span class="n">sqlite3_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> + + <span class="k">def</span> <span class="nf">teardown_request</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exception</span><span class="p">):</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="n">_request_ctx_stack</span><span class="o">.</span><span class="n">top</span> + <span class="n">ctx</span><span class="o">.</span><span class="n">sqlite3_db</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> + + <span class="k">def</span> <span class="nf">get_db</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="n">_request_ctx_stack</span><span class="o">.</span><span class="n">top</span> + <span class="k">if</span> <span class="n">ctx</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> + <span class="k">return</span> <span class="n">ctx</span><span class="o">.</span><span class="n">sqlite3_db</span> +</pre></div> +</div> +<p>The user could then initialize the extension in one file:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">manager</span> <span class="o">=</span> <span class="n">SQLite3</span><span class="p">()</span> +</pre></div> +</div> +<p>and bind their app to the extension in another file:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">manager</span><span class="o">.</span><span class="n">init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span> +</pre></div> +</div> +</div> +<div class="section" id="end-of-request-behavior"> +<h2>End-Of-Request Behavior<a class="headerlink" href="#end-of-request-behavior" title="Permalink to this headline">¶</a></h2> +<p>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:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">close_connection</span><span class="p">(</span><span class="n">response</span><span class="p">):</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="n">_request_ctx_stack</span><span class="o">.</span><span class="n">top</span> + <span class="n">ctx</span><span class="o">.</span><span class="n">sqlite3_db</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> + <span class="k">return</span> <span class="n">response</span> + +<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s">'teardown_request'</span><span class="p">):</span> + <span class="n">app</span><span class="o">.</span><span class="n">teardown_request</span><span class="p">(</span><span class="n">close_connection</span><span class="p">)</span> +<span class="k">else</span><span class="p">:</span> + <span class="n">app</span><span class="o">.</span><span class="n">after_request</span><span class="p">(</span><span class="n">close_connection</span><span class="p">)</span> +</pre></div> +</div> +<p>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.</p> +</div> +<div class="section" id="learn-from-others"> +<h2>Learn from Others<a class="headerlink" href="#learn-from-others" title="Permalink to this headline">¶</a></h2> +<p>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 <a class="reference external" href="http://flask.pocoo.org/extensions/">Flask Extension Registry</a>. If you feel +lost there is still the <a class="reference external" href="http://flask.pocoo.org/mailinglist/">mailinglist</a> and the <a class="reference external" href="http://flask.pocoo.org/community/irc/">IRC channel</a> 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.</p> +<p>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.</p> +<p>The best Flask extensions are extensions that share common idioms for the +API. And this can only work if collaboration happens early.</p> +</div> +<div class="section" id="approved-extensions"> +<h2>Approved Extensions<a class="headerlink" href="#approved-extensions" title="Permalink to this headline">¶</a></h2> +<p>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 <a class="reference external" href="http://flask.pocoo.org/extensions/">Flask +Extension Registry</a> and marked appropriately. If you want your own +extension to be approved you have to follow these guidelines:</p> +<ol class="arabic simple"> +<li>An approved Flask extension must provide exactly one package or module +named <tt class="docutils literal"><span class="pre">flask_extensionname</span></tt>. They might also reside inside a +<tt class="docutils literal"><span class="pre">flaskext</span></tt> namespace packages though this is discouraged now.</li> +<li>It must ship a testing suite that can either be invoked with <tt class="docutils literal"><span class="pre">make</span> <span class="pre">test</span></tt> +or <tt class="docutils literal"><span class="pre">python</span> <span class="pre">setup.py</span> <span class="pre">test</span></tt>. For test suites invoked with <tt class="docutils literal"><span class="pre">make</span> +<span class="pre">test</span></tt> the extension has to ensure that all dependencies for the test +are installed automatically, in case of <tt class="docutils literal"><span class="pre">python</span> <span class="pre">setup.py</span> <span class="pre">test</span></tt> +dependencies for tests alone can be specified in the <cite>setup.py</cite> +file. The test suite also has to be part of the distribution.</li> +<li>APIs of approved extensions will be checked for the following +characteristics:<ul> +<li>an approved extension has to support multiple applications +running in the same Python process.</li> +<li>it must be possible to use the factory pattern for creating +applications.</li> +</ul> +</li> +<li>The license must be BSD/MIT/WTFPL licensed.</li> +<li>The naming scheme for official extensions is <em>Flask-ExtensionName</em> or +<em>ExtensionName-Flask</em>.</li> +<li>Approved extensions must define all their dependencies in the +<cite>setup.py</cite> file unless a dependency cannot be met because it is not +available on PyPI.</li> +<li>The extension must have documentation that uses one of the two Flask +themes for Sphinx documentation.</li> +<li>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 +(<tt class="docutils literal"><span class="pre">PackageName==dev</span></tt>).</li> +<li>The <tt class="docutils literal"><span class="pre">zip_safe</span></tt> flag in the setup script must be set to <tt class="docutils literal"><span class="pre">False</span></tt>, +even if the extension would be safe for zipping.</li> +<li>An extension currently has to support Python 2.5, 2.6 as well as +Python 2.7</li> +</ol> +</div> +<div class="section" id="extension-import-transition"> +<span id="ext-import-transition"></span><h2>Extension Import Transition<a class="headerlink" href="#extension-import-transition" title="Permalink to this headline">¶</a></h2> +<p>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.</p> +<p>Instead we now recommend naming packages <tt class="docutils literal"><span class="pre">flask_foo</span></tt> instead of the now +deprecated <tt class="docutils literal"><span class="pre">flaskext.foo</span></tt>. Flask 0.8 introduces a redirect import +system that lets uses import from <tt class="docutils literal"><span class="pre">flask.ext.foo</span></tt> and it will try +<tt class="docutils literal"><span class="pre">flask_foo</span></tt> first and if that fails <tt class="docutils literal"><span class="pre">flaskext.foo</span></tt>.</p> +<p>Flask extensions should urge users to import from <tt class="docutils literal"><span class="pre">flask.ext.foo</span></tt> +instead of <tt class="docutils literal"><span class="pre">flask_foo</span></tt> or <tt class="docutils literal"><span class="pre">flaskext_foo</span></tt> so that extensions can +transition to the new package name without affecting users.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="index.html"> + <img class="logo" src="_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Flask Extension Development</a><ul> +<li><a class="reference internal" href="#anatomy-of-an-extension">Anatomy of an Extension</a></li> +<li><a class="reference internal" href="#hello-flaskext">“Hello Flaskext!”</a><ul> +<li><a class="reference internal" href="#setup-py">setup.py</a></li> +<li><a class="reference internal" href="#flask-sqlite3-py">flask_sqlite3.py</a></li> +</ul> +</li> +<li><a class="reference internal" href="#initializing-extensions">Initializing Extensions</a></li> +<li><a class="reference internal" href="#the-extension-code">The Extension Code</a></li> +<li><a class="reference internal" href="#adding-an-init-app-function">Adding an <cite>init_app</cite> Function</a></li> +<li><a class="reference internal" href="#end-of-request-behavior">End-Of-Request Behavior</a></li> +<li><a class="reference internal" href="#learn-from-others">Learn from Others</a></li> +<li><a class="reference internal" href="#approved-extensions">Approved Extensions</a></li> +<li><a class="reference internal" href="#extension-import-transition">Extension Import Transition</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="index.html">Documentation overview</a><ul> + <li>Previous: <a href="unicode.html" title="previous chapter">Unicode in Flask</a></li> + <li>Next: <a href="styleguide.html" title="next chapter">Pocoo Styleguide</a></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="_sources/extensiondev.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file |