Browse Source

Merge branch 'master' into AvivC-improve-docs-in-Flask.preprocess_request

pull/2258/head
David Lord 8 years ago
parent
commit
bc7dae3d5a
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
  1. 1
      .gitattributes
  2. 2
      .github/ISSUE_TEMPLATE.rst
  3. 6
      .gitignore
  4. 15
      .travis.yml
  5. 5
      AUTHORS
  6. 110
      CHANGES
  7. 64
      CONTRIBUTING.rst
  8. 18
      MANIFEST.in
  9. 6
      Makefile
  10. 6
      README
  11. 6
      docs/_templates/sidebarintro.html
  12. 22
      docs/advanced_foreword.rst
  13. 79
      docs/api.rst
  14. 9
      docs/appcontext.rst
  15. 4
      docs/becomingbig.rst
  16. 21
      docs/blueprints.rst
  17. 187
      docs/cli.rst
  18. 108
      docs/conf.py
  19. 36
      docs/config.rst
  20. 8
      docs/deploying/fastcgi.rst
  21. 4
      docs/deploying/index.rst
  22. 14
      docs/deploying/mod_wsgi.rst
  23. 26
      docs/deploying/uwsgi.rst
  24. 11
      docs/deploying/wsgi-standalone.rst
  25. 68
      docs/errorhandling.rst
  26. 38
      docs/extensiondev.rst
  27. 18
      docs/extensions.rst
  28. 2
      docs/htmlfaq.rst
  29. 55
      docs/installation.rst
  30. 2
      docs/patterns/apierrors.rst
  31. 14
      docs/patterns/appdispatch.rst
  32. 7
      docs/patterns/appfactories.rst
  33. 2
      docs/patterns/celery.rst
  34. 6
      docs/patterns/deferredcallbacks.rst
  35. 101
      docs/patterns/distribute.rst
  36. 38
      docs/patterns/fabric.rst
  37. 2
      docs/patterns/favicon.rst
  38. 22
      docs/patterns/fileuploads.rst
  39. 6
      docs/patterns/flashing.rst
  40. 1
      docs/patterns/index.rst
  41. 2
      docs/patterns/jquery.rst
  42. 15
      docs/patterns/lazyloading.rst
  43. 52
      docs/patterns/packages.rst
  44. 10
      docs/patterns/sqlalchemy.rst
  45. 33
      docs/patterns/sqlite3.rst
  46. 17
      docs/patterns/subclassing.rst
  47. 27
      docs/patterns/viewdecorators.rst
  48. 12
      docs/patterns/wtforms.rst
  49. 39
      docs/python3.rst
  50. 181
      docs/quickstart.rst
  51. 2
      docs/reqcontext.rst
  52. 89
      docs/security.rst
  53. 18
      docs/server.rst
  54. 2
      docs/shell.rst
  55. 6
      docs/signals.rst
  56. 2
      docs/styleguide.rst
  57. 32
      docs/testing.rst
  58. 4
      docs/tutorial/css.rst
  59. 31
      docs/tutorial/dbcon.rst
  60. 33
      docs/tutorial/dbinit.rst
  61. 26
      docs/tutorial/folders.rst
  62. 3
      docs/tutorial/index.rst
  63. 11
      docs/tutorial/introduction.rst
  64. 108
      docs/tutorial/packaging.rst
  65. 10
      docs/tutorial/schema.rst
  66. 70
      docs/tutorial/setup.rst
  67. 19
      docs/tutorial/templates.rst
  68. 86
      docs/tutorial/testing.rst
  69. 43
      docs/tutorial/views.rst
  70. 113
      docs/upgrading.rst
  71. 1
      examples/flaskr/.gitignore
  72. 3
      examples/flaskr/MANIFEST.in
  73. 18
      examples/flaskr/README
  74. 1
      examples/flaskr/flaskr/__init__.py
  75. 0
      examples/flaskr/flaskr/flaskr.py
  76. 0
      examples/flaskr/flaskr/schema.sql
  77. 0
      examples/flaskr/flaskr/static/style.css
  78. 0
      examples/flaskr/flaskr/templates/layout.html
  79. 0
      examples/flaskr/flaskr/templates/login.html
  80. 4
      examples/flaskr/flaskr/templates/show_entries.html
  81. 2
      examples/flaskr/setup.cfg
  82. 16
      examples/flaskr/setup.py
  83. 5
      examples/flaskr/tests/test_flaskr.py
  84. 2
      examples/minitwit/.gitignore
  85. 3
      examples/minitwit/MANIFEST.in
  86. 18
      examples/minitwit/README
  87. 1
      examples/minitwit/minitwit/__init__.py
  88. 2
      examples/minitwit/minitwit/minitwit.py
  89. 0
      examples/minitwit/minitwit/schema.sql
  90. 0
      examples/minitwit/minitwit/static/style.css
  91. 0
      examples/minitwit/minitwit/templates/layout.html
  92. 0
      examples/minitwit/minitwit/templates/login.html
  93. 0
      examples/minitwit/minitwit/templates/register.html
  94. 0
      examples/minitwit/minitwit/templates/timeline.html
  95. 2
      examples/minitwit/setup.cfg
  96. 16
      examples/minitwit/setup.py
  97. 2
      examples/minitwit/tests/test_minitwit.py
  98. 10
      examples/patterns/largerapp/setup.py
  99. 12
      examples/patterns/largerapp/tests/test_largerapp.py
  100. 4
      examples/patterns/largerapp/yourapplication/__init__.py
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitattributes vendored

@ -0,0 +1 @@
CHANGES merge=union

2
.github/ISSUE_TEMPLATE.rst

@ -0,0 +1,2 @@
The issue tracker is a tool to address bugs.
Please use the #pocoo IRC channel on freenode or Stack Overflow for questions.

6
.gitignore vendored

@ -11,3 +11,9 @@ _mailinglist
.tox .tox
.cache/ .cache/
.idea/ .idea/
# Coverage reports
htmlcov
.coverage
.coverage.*
*,cover

15
.travis.yml

@ -8,22 +8,35 @@ python:
- "3.3" - "3.3"
- "3.4" - "3.4"
- "3.5" - "3.5"
- "3.6"
env: env:
- REQUIREMENTS=lowest - REQUIREMENTS=lowest
- REQUIREMENTS=lowest-simplejson
- REQUIREMENTS=release - REQUIREMENTS=release
- REQUIREMENTS=release-simplejson
- REQUIREMENTS=devel - REQUIREMENTS=devel
- REQUIREMENTS=devel-simplejson
matrix: matrix:
exclude: exclude:
# Python 3 support currently does not work with lowest requirements # Python 3 support currently does not work with lowest requirements
- python: "3.3" - python: "3.3"
env: REQUIREMENTS=lowest env: REQUIREMENTS=lowest
- python: "3.3"
env: REQUIREMENTS=lowest-simplejson
- python: "3.4" - python: "3.4"
env: REQUIREMENTS=lowest env: REQUIREMENTS=lowest
- python: "3.4"
env: REQUIREMENTS=lowest-simplejson
- python: "3.5" - python: "3.5"
env: REQUIREMENTS=lowest env: REQUIREMENTS=lowest
- python: "3.5"
env: REQUIREMENTS=lowest-simplejson
- python: "3.6"
env: REQUIREMENTS=lowest
- python: "3.6"
env: REQUIREMENTS=lowest-simplejson
install: install:
- pip install tox - pip install tox

5
AUTHORS

@ -15,9 +15,13 @@ Patches and Suggestions
- Chris Grindstaff - Chris Grindstaff
- Christopher Grebs - Christopher Grebs
- Daniel Neuhäuser - Daniel Neuhäuser
- Dan Sully
- David Lord @davidism
- Edmond Burnett - Edmond Burnett
- Florent Xicluna - Florent Xicluna
- Georg Brandl - Georg Brandl
- Jeff Widman @jeffwidman
- Joshua Bronson @jab
- Justin Quick - Justin Quick
- Kenneth Reitz - Kenneth Reitz
- Keyan Pishdadian - Keyan Pishdadian
@ -32,4 +36,3 @@ Patches and Suggestions
- Stephane Wirtel - Stephane Wirtel
- Thomas Schranz - Thomas Schranz
- Zhao Xiaohong - Zhao Xiaohong
- David Lord @davidism

110
CHANGES

@ -3,11 +3,103 @@ Flask Changelog
Here you can see the full list of changes between each Flask release. Here you can see the full list of changes between each Flask release.
Version 1.0 Version 0.13
----------- ------------
Major release, unreleased
- Make `app.run()` into a noop if a Flask application is run from the
development server on the command line. This avoids some behavior that
was confusing to debug for newcomers.
- Change default configuration `JSONIFY_PRETTYPRINT_REGULAR=False`. jsonify()
method returns compressed response by default, and pretty response in
debug mode.
- Change Flask.__init__ to accept two new keyword arguments, ``host_matching``
and ``static_host``. This enables ``host_matching`` to be set properly by the
time the constructor adds the static route, and enables the static route to
be properly associated with the required host. (``#1559``)
- ``send_file`` supports Unicode in ``attachment_filename``. (`#2223`_)
- Pass ``_scheme`` argument from ``url_for`` to ``handle_build_error``.
(`#2017`_)
- Add support for ``provide_automatic_options`` in ``add_url_rule`` to disable
adding OPTIONS method when the ``view_func`` argument is not a class.
(`#1489`_).
- ``MethodView`` can inherit method handlers from base classes. (`#1936`_)
- Errors caused while opening the session at the beginning of the request are
handled by the app's error handlers. (`#2254`_)
- Blueprints gained ``json_encoder`` and ``json_decoder`` attributes to
override the app's encoder and decoder. (`#1898`_)
- ``Flask.make_response`` raises ``TypeError`` instead of ``ValueError`` for
bad response types. The error messages have been improved to describe why the
type is invalid. (`#2256`_)
.. _#1489: https://github.com/pallets/flask/pull/1489
.. _#1898: https://github.com/pallets/flask/pull/1898
.. _#1936: https://github.com/pallets/flask/pull/1936
.. _#2017: https://github.com/pallets/flask/pull/2017
.. _#2223: https://github.com/pallets/flask/pull/2223
.. _#2254: https://github.com/pallets/flask/pull/2254
.. _#2256: https://github.com/pallets/flask/pull/2256
Version 0.12.1
--------------
Bugfix release, released on March 31st 2017
- Prevent `flask run` from showing a NoAppException when an ImportError occurs
within the imported application module.
- Fix encoding behavior of ``app.config.from_pyfile`` for Python 3. Fix
``#2118``.
- Use the ``SERVER_NAME`` config if it is present as default values for
``app.run``. ``#2109``, ``#2152``
- Call `ctx.auto_pop` with the exception object instead of `None`, in the
event that a `BaseException` such as `KeyboardInterrupt` is raised in a
request handler.
Version 0.12
------------
Released on December 21st 2016, codename Punsch.
- the cli command now responds to `--version`.
- Mimetype guessing and ETag generation for file-like objects in ``send_file``
has been removed, as per issue ``#104``. See pull request ``#1849``.
- Mimetype guessing in ``send_file`` now fails loudly and doesn't fall back to
``application/octet-stream``. See pull request ``#1988``.
- Make ``flask.safe_join`` able to join multiple paths like ``os.path.join``
(pull request ``#1730``).
- Revert a behavior change that made the dev server crash instead of returning
a Internal Server Error (pull request ``#2006``).
- Correctly invoke response handlers for both regular request dispatching as
well as error handlers.
- Disable logger propagation by default for the app logger.
- Add support for range requests in ``send_file``.
- ``app.test_client`` includes preset default environment, which can now be
directly set, instead of per ``client.get``.
Version 0.11.2
--------------
Bugfix release, unreleased
- Fix crash when running under PyPy3, see pull request ``#1814``.
Version 0.11.1
--------------
Bugfix release, released on June 7th 2016.
- Fixed a bug that prevented ``FLASK_APP=foobar/__init__.py`` from working. See
pull request ``#1872``.
Version 0.11
------------
(release date to be announced, codename to be selected) Released on May 29th 2016, codename Absinthe.
- Added support to serializing top-level arrays to :func:`flask.jsonify`. This
introduces a security risk in ancient browsers. See
:ref:`json-security` for details.
- Added before_render_template signal. - Added before_render_template signal.
- Added `**kwargs` to :meth:`flask.Test.test_client` to support passing - Added `**kwargs` to :meth:`flask.Test.test_client` to support passing
additional keyword arguments to the constructor of additional keyword arguments to the constructor of
@ -23,7 +115,7 @@ Version 1.0
from a view function. from a view function.
- Added :meth:`flask.Config.from_json`. - Added :meth:`flask.Config.from_json`.
- Added :attr:`flask.Flask.config_class`. - Added :attr:`flask.Flask.config_class`.
- Added :meth:`flask.config.Config.get_namespace`. - Added :meth:`flask.Config.get_namespace`.
- Templates are no longer automatically reloaded outside of debug mode. This - Templates are no longer automatically reloaded outside of debug mode. This
can be configured with the new ``TEMPLATES_AUTO_RELOAD`` config key. can be configured with the new ``TEMPLATES_AUTO_RELOAD`` config key.
- Added a workaround for a limitation in Python 3.3's namespace loader. - Added a workaround for a limitation in Python 3.3's namespace loader.
@ -57,7 +149,7 @@ Version 1.0
- JSON responses are now terminated with a newline character, because it is a - JSON responses are now terminated with a newline character, because it is a
convention that UNIX text files end with a newline and some clients don't convention that UNIX text files end with a newline and some clients don't
deal well when this newline is missing. See deal well when this newline is missing. See
https://github.com/mitsuhiko/flask/pull/1262 -- this came up originally as a https://github.com/pallets/flask/pull/1262 -- this came up originally as a
part of https://github.com/kennethreitz/httpbin/issues/168 part of https://github.com/kennethreitz/httpbin/issues/168
- The automatically provided ``OPTIONS`` method is now correctly disabled if - The automatically provided ``OPTIONS`` method is now correctly disabled if
the user registered an overriding rule with the lowercase-version the user registered an overriding rule with the lowercase-version
@ -70,6 +162,12 @@ Version 1.0
- ``flask.g`` now has ``pop()`` and ``setdefault`` methods. - ``flask.g`` now has ``pop()`` and ``setdefault`` methods.
- Turn on autoescape for ``flask.templating.render_template_string`` by default - Turn on autoescape for ``flask.templating.render_template_string`` by default
(pull request ``#1515``). (pull request ``#1515``).
- ``flask.ext`` is now deprecated (pull request ``#1484``).
- ``send_from_directory`` now raises BadRequest if the filename is invalid on
the server OS (pull request ``#1763``).
- Added the ``JSONIFY_MIMETYPE`` configuration variable (pull request ``#1728``).
- Exceptions during teardown handling will no longer leave bad application
contexts lingering around.
Version 0.10.2 Version 0.10.2
-------------- --------------
@ -292,7 +390,7 @@ Released on September 29th 2011, codename Rakija
- Applications now not only have a root path where the resources and modules - Applications now not only have a root path where the resources and modules
are located but also an instance path which is the designated place to are located but also an instance path which is the designated place to
drop files that are modified at runtime (uploads etc.). Also this is drop files that are modified at runtime (uploads etc.). Also this is
conceptionally only instance depending and outside version control so it's conceptually only instance depending and outside version control so it's
the perfect place to put configuration files etc. For more information the perfect place to put configuration files etc. For more information
see :ref:`instance-folders`. see :ref:`instance-folders`.
- Added the ``APPLICATION_ROOT`` configuration variable. - Added the ``APPLICATION_ROOT`` configuration variable.

64
CONTRIBUTING.rst

@ -10,7 +10,7 @@ Support questions
Please, don't use the issue tracker for this. Check whether the ``#pocoo`` IRC Please, don't use the issue tracker for this. Check whether the ``#pocoo`` IRC
channel on Freenode can help with your issue. If your problem is not strictly channel on Freenode can help with your issue. If your problem is not strictly
Werkzeug or Flask specific, ``#python`` is generally more active. Werkzeug or Flask specific, ``#python`` is generally more active.
`StackOverflow <https://stackoverflow.com/>`_ is also worth considering. `Stack Overflow <https://stackoverflow.com/>`_ is also worth considering.
Reporting issues Reporting issues
================ ================
@ -28,7 +28,7 @@ Submitting patches
clearly under which circumstances the bug happens. Make sure the test fails clearly under which circumstances the bug happens. Make sure the test fails
without your patch. without your patch.
- Try to follow `PEP8 <http://legacy.python.org/dev/peps/pep-0008/>`_, but you - Try to follow `PEP8 <https://www.python.org/dev/peps/pep-0008/>`_, but you
may ignore the line-length-limit if following it would make the code uglier. may ignore the line-length-limit if following it would make the code uglier.
@ -36,16 +36,16 @@ Running the testsuite
--------------------- ---------------------
You probably want to set up a `virtualenv You probably want to set up a `virtualenv
<http://virtualenv.readthedocs.org/en/latest/index.html>`_. <https://virtualenv.readthedocs.io/en/latest/index.html>`_.
The minimal requirement for running the testsuite is ``py.test``. You can The minimal requirement for running the testsuite is ``pytest``. You can
install it with:: install it with::
pip install pytest pip install pytest
Clone this repository:: Clone this repository::
git clone https://github.com/mitsuhiko/flask.git git clone https://github.com/pallets/flask.git
Install Flask as an editable package using the current source:: Install Flask as an editable package using the current source::
@ -54,19 +54,61 @@ Install Flask as an editable package using the current source::
Then you can run the testsuite with:: Then you can run the testsuite with::
py.test pytest
With only py.test installed, a large part of the testsuite will get skipped With only pytest installed, a large part of the testsuite will get skipped
though. Whether this is relevant depends on which part of Flask you're working though. Whether this is relevant depends on which part of Flask you're working
on. Travis is set up to run the full testsuite when you submit your pull on. Travis is set up to run the full testsuite when you submit your pull
request anyways. request anyways.
If you really want to test everything, you will have to install ``tox`` instead If you really want to test everything, you will have to install ``tox`` instead
of ``pytest``. Currently we're depending on a development version of Tox of ``pytest``. You can install it with::
because the released version is missing features we absolutely need. You can
install it with::
pip install hg+https://bitbucket.org/hpk42/tox pip install tox
The ``tox`` command will then run all tests against multiple combinations The ``tox`` command will then run all tests against multiple combinations
Python versions and dependency versions. Python versions and dependency versions.
Running test coverage
---------------------
Generating a report of lines that do not have unit test coverage can indicate where
to start contributing. ``pytest`` integrates with ``coverage.py``, using the ``pytest-cov``
plugin. This assumes you have already run the testsuite (see previous section)::
pip install pytest-cov
After this has been installed, you can output a report to the command line using this command::
pytest --cov=flask tests/
Generate a HTML report can be done using this command::
pytest --cov-report html --cov=flask tests/
Full docs on ``coverage.py`` are here: https://coverage.readthedocs.io
Caution
=======
pushing
-------
This repository contains several zero-padded file modes that may cause issues when pushing this repository to git hosts other than github. Fixing this is destructive to the commit history, so we suggest ignoring these warnings. If it fails to push and you're using a self-hosted git service like Gitlab, you can turn off repository checks in the admin panel.
cloning
-------
The zero-padded file modes files above can cause issues while cloning, too. If you have
::
[fetch]
fsckobjects = true
or
::
[receive]
fsckObjects = true
set in your git configuration file, cloning this repository will fail. The only solution is to set both of the above settings to false while cloning, and then setting them back to true after the cloning is finished.

18
MANIFEST.in

@ -1,13 +1,11 @@
include Makefile CHANGES LICENSE AUTHORS include Makefile CHANGES LICENSE AUTHORS
recursive-include artwork *
recursive-include tests * graft artwork
recursive-include examples * graft tests
recursive-include docs * graft examples
recursive-exclude docs *.pyc graft docs
recursive-exclude docs *.pyo
recursive-exclude tests *.pyc global-exclude *.py[co]
recursive-exclude tests *.pyo
recursive-exclude examples *.pyc
recursive-exclude examples *.pyo
prune docs/_build prune docs/_build
prune docs/_themes prune docs/_themes

6
Makefile

@ -3,10 +3,8 @@
all: clean-pyc test all: clean-pyc test
test: test:
py.test tests examples pip install -r test-requirements.txt
tox -e py-release
tox-test:
tox
audit: audit:
python setup.py audit python setup.py audit

6
README

@ -33,9 +33,11 @@
Good that you're asking. The tests are in the Good that you're asking. The tests are in the
tests/ folder. To run the tests use the tests/ folder. To run the tests use the
`py.test` testing tool: `pytest` testing tool:
$ py.test $ pytest
Details on contributing can be found in CONTRIBUTING.rst
~ Where can I get help? ~ Where can I get help?

6
docs/_templates/sidebarintro.html vendored

@ -16,7 +16,7 @@
<h3>Useful Links</h3> <h3>Useful Links</h3>
<ul> <ul>
<li><a href="http://flask.pocoo.org/">The Flask Website</a></li> <li><a href="http://flask.pocoo.org/">The Flask Website</a></li>
<li><a href="http://pypi.python.org/pypi/Flask">Flask @ PyPI</a></li> <li><a href="https://pypi.python.org/pypi/Flask">Flask @ PyPI</a></li>
<li><a href="http://github.com/mitsuhiko/flask">Flask @ GitHub</a></li> <li><a href="https://github.com/pallets/flask">Flask @ GitHub</a></li>
<li><a href="http://github.com/mitsuhiko/flask/issues">Issue Tracker</a></li> <li><a href="https://github.com/pallets/flask/issues">Issue Tracker</a></li>
</ul> </ul>

22
docs/advanced_foreword.rst

@ -46,24 +46,10 @@ spam, links to malicious software, and the like.
Flask is no different from any other framework in that you the developer must Flask is no different from any other framework in that you the developer must
build with caution, watching for exploits when building to your requirements. build with caution, watching for exploits when building to your requirements.
The Status of Python 3 Python 3 Support in Flask
---------------------- -------------------------
Currently the Python community is in the process of improving libraries to
support the new iteration of the Python programming language. While the
situation is greatly improving there are still some issues that make it
hard for users to switch over to Python 3 just now. These problems are
partially caused by changes in the language that went unreviewed for too
long, partially also because we have not quite worked out how the lower-
level API should change to account for the Unicode differences in Python 3.
We strongly recommend using Python 2.7 with activated Python 3
warnings during development. If you plan on upgrading to Python 3 in the
near future we strongly recommend that you read `How to write forwards
compatible Python code
<http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/>`_.
If you do want to dive into Python 3 already have a look at the Flask, its dependencies, and most Flask extensions all support Python 3.
:ref:`python3-support` page. If you want to use Flask with Python 3 have a look at the :ref:`python3-support` page.
Continue to :ref:`installation` or the :ref:`quickstart`. Continue to :ref:`installation` or the :ref:`quickstart`.

79
docs/api.rst

@ -30,61 +30,12 @@ Incoming Request Data
.. autoclass:: Request .. autoclass:: Request
:members: :members:
:inherited-members:
.. attribute:: form
A :class:`~werkzeug.datastructures.MultiDict` with the parsed form data from ``POST``
or ``PUT`` requests. Please keep in mind that file uploads will not
end up here, but instead in the :attr:`files` attribute.
.. attribute:: args
A :class:`~werkzeug.datastructures.MultiDict` with the parsed contents of the query
string. (The part in the URL after the question mark).
.. attribute:: values
A :class:`~werkzeug.datastructures.CombinedMultiDict` with the contents of both
:attr:`form` and :attr:`args`.
.. attribute:: cookies
A :class:`dict` with the contents of all cookies transmitted with
the request.
.. attribute:: stream
If the incoming form data was not encoded with a known mimetype
the data is stored unmodified in this stream for consumption. Most
of the time it is a better idea to use :attr:`data` which will give
you that data as a string. The stream only returns the data once.
.. attribute:: headers
The incoming request headers as a dictionary like object.
.. attribute:: data
Contains the incoming request data as string in case it came with
a mimetype Flask does not handle.
.. attribute:: files
A :class:`~werkzeug.datastructures.MultiDict` with files uploaded as part of a
``POST`` or ``PUT`` request. Each file is stored as
:class:`~werkzeug.datastructures.FileStorage` object. It basically behaves like a
standard file object you know from Python, with the difference that
it also has a :meth:`~werkzeug.datastructures.FileStorage.save` function that can
store the file on the filesystem.
.. attribute:: environ .. attribute:: environ
The underlying WSGI environment. The underlying WSGI environment.
.. attribute:: method
The current request method (``POST``, ``GET`` etc.)
.. attribute:: path .. attribute:: path
.. attribute:: full_path .. attribute:: full_path
.. attribute:: script_root .. attribute:: script_root
@ -114,15 +65,8 @@ Incoming Request Data
`url_root` ``u'http://www.example.com/myapplication/'`` `url_root` ``u'http://www.example.com/myapplication/'``
============= ====================================================== ============= ======================================================
.. attribute:: is_xhr
``True`` if the request was triggered via a JavaScript
`XMLHttpRequest`. This only works with libraries that support the
``X-Requested-With`` header and set it to `XMLHttpRequest`.
Libraries that do that are prototype, jQuery and Mochikit and
probably some more.
.. class:: request .. attribute:: request
To access incoming request data, you can use the global `request` To access incoming request data, you can use the global `request`
object. Flask parses incoming request data for you and gives you object. Flask parses incoming request data for you and gives you
@ -289,7 +233,7 @@ thing, like it does for :class:`request` and :class:`session`.
It's now also possible to use the ``in`` operator on it to see if an It's now also possible to use the ``in`` operator on it to see if an
attribute is defined and it yields all keys on iteration. attribute is defined and it yields all keys on iteration.
As of 1.0 you can use :meth:`pop` and :meth:`setdefault` in the same As of 0.11 you can use :meth:`pop` and :meth:`setdefault` in the same
way you would use them on a dictionary. way you would use them on a dictionary.
This is a proxy. See :ref:`notes-on-proxies` for more information. This is a proxy. See :ref:`notes-on-proxies` for more information.
@ -316,13 +260,7 @@ Useful Functions and Classes
.. autofunction:: url_for .. autofunction:: url_for
.. function:: abort(code) .. autofunction:: abort
Raises an :exc:`~werkzeug.exceptions.HTTPException` for the given
status code. For example to abort request handling with a page not
found exception, you would call ``abort(404)``.
:param code: the HTTP error code.
.. autofunction:: redirect .. autofunction:: redirect
@ -751,6 +689,8 @@ The following converters are available:
`int` accepts integers `int` accepts integers
`float` like `int` but for floating point values `float` like `int` but for floating point values
`path` like the default but also accepts slashes `path` like the default but also accepts slashes
`any` matches one of the items provided
`uuid` accepts UUID strings
=========== =============================================== =========== ===============================================
Custom converters can be defined using :attr:`flask.Flask.url_map`. Custom converters can be defined using :attr:`flask.Flask.url_map`.
@ -890,13 +830,6 @@ Command Line Interface
Marks a function so that an instance of :class:`ScriptInfo` is passed Marks a function so that an instance of :class:`ScriptInfo` is passed
as first argument to the click callback. as first argument to the click callback.
.. autofunction:: script_info_option
A special decorator that informs a click callback to be passed the
script info object as first argument. This is normally not useful
unless you implement very special commands like the run command which
does not want the application to be loaded yet.
.. autodata:: run_command .. autodata:: run_command
.. autodata:: shell_command .. autodata:: shell_command

9
docs/appcontext.rst

@ -26,8 +26,8 @@ In contrast, during request handling, a couple of other rules exist:
There is a third state which is sitting in between a little bit. There is a third state which is sitting in between a little bit.
Sometimes you are dealing with an application in a way that is similar to Sometimes you are dealing with an application in a way that is similar to
how you interact with applications during request handling just that there how you interact with applications during request handling; just that there
is no request active. Consider for instance that you're sitting in an is no request active. Consider, for instance, that you're sitting in an
interactive Python shell and interacting with the application, or a interactive Python shell and interacting with the application, or a
command line application. command line application.
@ -74,6 +74,11 @@ The application context is also used by the :func:`~flask.url_for`
function in case a ``SERVER_NAME`` was configured. This allows you to function in case a ``SERVER_NAME`` was configured. This allows you to
generate URLs even in the absence of a request. generate URLs even in the absence of a request.
If no request context has been pushed and an application context has
not been explicitly set, a ``RuntimeError`` will be raised. ::
RuntimeError: Working outside of application context.
Locality of the Context Locality of the Context
----------------------- -----------------------

4
docs/becomingbig.rst

@ -12,7 +12,7 @@ Flask started in part to demonstrate how to build your own framework on top of
existing well-used tools Werkzeug (WSGI) and Jinja (templating), and as it existing well-used tools Werkzeug (WSGI) and Jinja (templating), and as it
developed, it became useful to a wide audience. As you grow your codebase, developed, it became useful to a wide audience. As you grow your codebase,
don't just use Flask -- understand it. Read the source. Flask's code is don't just use Flask -- understand it. Read the source. Flask's code is
written to be read; it's documentation is published so you can use its internal written to be read; its documentation is published so you can use its internal
APIs. Flask sticks to documented APIs in upstream libraries, and documents its APIs. Flask sticks to documented APIs in upstream libraries, and documents its
internal utilities so that you can find the hook points needed for your internal utilities so that you can find the hook points needed for your
project. project.
@ -35,7 +35,7 @@ Subclass.
The :class:`~flask.Flask` class has many methods designed for subclassing. You The :class:`~flask.Flask` class has many methods designed for subclassing. You
can quickly add or customize behavior by subclassing :class:`~flask.Flask` (see can quickly add or customize behavior by subclassing :class:`~flask.Flask` (see
the linked method docs) and using that subclass wherever you instantiate an the linked method docs) and using that subclass wherever you instantiate an
application class. This works well with :ref:`app-factories`. application class. This works well with :ref:`app-factories`. See :doc:`/patterns/subclassing` for an example.
Wrap with middleware. Wrap with middleware.
--------------------- ---------------------

21
docs/blueprints.rst

@ -176,16 +176,25 @@ the `template_folder` parameter to the :class:`Blueprint` constructor::
admin = Blueprint('admin', __name__, template_folder='templates') admin = Blueprint('admin', __name__, template_folder='templates')
As for static files, the path can be absolute or relative to the blueprint For static files, the path can be absolute or relative to the blueprint
resource folder. The template folder is added to the searchpath of resource folder.
templates but with a lower priority than the actual application's template
folder. That way you can easily override templates that a blueprint The template folder is added to the search path of templates but with a lower
provides in the actual application. priority than the actual application's template folder. That way you can
easily override templates that a blueprint provides in the actual application.
This also means that if you don't want a blueprint template to be accidentally
overridden, make sure that no other blueprint or actual application template
has the same relative path. When multiple blueprints provide the same relative
template path the first blueprint registered takes precedence over the others.
So if you have a blueprint in the folder ``yourapplication/admin`` and you So if you have a blueprint in the folder ``yourapplication/admin`` and you
want to render the template ``'admin/index.html'`` and you have provided want to render the template ``'admin/index.html'`` and you have provided
``templates`` as a `template_folder` you will have to create a file like ``templates`` as a `template_folder` you will have to create a file like
this: :file:`yourapplication/admin/templates/admin/index.html`. this: :file:`yourapplication/admin/templates/admin/index.html`. The reason
for the extra ``admin`` folder is to avoid getting our template overridden
by a template named ``index.html`` in the actual application template
folder.
To further reiterate this: if you have a blueprint named ``admin`` and you To further reiterate this: if you have a blueprint named ``admin`` and you
want to render a template called :file:`index.html` which is specific to this want to render a template called :file:`index.html` which is specific to this

187
docs/cli.rst

@ -3,11 +3,11 @@
Command Line Interface Command Line Interface
====================== ======================
.. versionadded:: 1.0 .. versionadded:: 0.11
.. currentmodule:: flask .. currentmodule:: flask
One of the nice new features in Flask 1.0 is the built-in integration of One of the nice new features in Flask 0.11 is the built-in integration of
the `click <http://click.pocoo.org/>`_ command line interface. This the `click <http://click.pocoo.org/>`_ command line interface. This
enables a wide range of new features for the Flask ecosystem and your own enables a wide range of new features for the Flask ecosystem and your own
applications. applications.
@ -15,41 +15,38 @@ applications.
Basic Usage Basic Usage
----------- -----------
After installation of Flask you will now find a :command:`flask` script installed After installation of Flask you will now find a :command:`flask` script
into your virtualenv. If you don't want to install Flask or you have a installed into your virtualenv. If you don't want to install Flask or you
special use-case you can also use ``python -m flask`` to accomplish exactly have a special use-case you can also use ``python -m flask`` to accomplish
the same. exactly the same.
The way this script works is by providing access to all the commands on The way this script works is by providing access to all the commands on
your Flask application's :attr:`Flask.cli` instance as well as some your Flask application's :attr:`Flask.cli` instance as well as some
built-in commands that are always there. Flask extensions can also built-in commands that are always there. Flask extensions can also
register more commands there if they desire so. register more commands there if they desire so.
For the :command:`flask` script to work, an application needs to be discovered. For the :command:`flask` script to work, an application needs to be
The two most common ways are either an environment variable discovered. This is achieved by exporting the ``FLASK_APP`` environment
(``FLASK_APP``) or the :option:`--app` / :option:`-a` parameter. It should be the variable. It can be either set to an import path or to a filename of a
import path for your application or the path to a Python file. In the Python module that contains a Flask application.
latter case Flask will attempt to setup the Python path for you
automatically and discover the module name but that might not always work.
In that imported file the name of the app needs to be called ``app`` or In that imported file the name of the app needs to be called ``app`` or
optionally be specified after a colon. optionally be specified after a colon. For instance
``mymodule:application`` would tell it to use the `application` object in
the :file:`mymodule.py` file.
Given a :file:`hello.py` file with the application in it named ``app`` this is Given a :file:`hello.py` file with the application in it named ``app``
how it can be run. this is how it can be run.
Environment variables (On Windows use ``set`` instead of ``export``):: Environment variables (On Windows use ``set`` instead of ``export``)::
export FLASK_APP=hello export FLASK_APP=hello
flask run flask run
Parameters:: Or with a filename::
flask --app=hello run export FLASK_APP=/path/to/hello.py
flask run
File names::
flask --app=hello.py run
Virtualenv Integration Virtualenv Integration
---------------------- ----------------------
@ -59,19 +56,33 @@ If you are constantly working with a virtualenv you can also put the
bottom of the file. That way every time you activate your virtualenv you bottom of the file. That way every time you activate your virtualenv you
automatically also activate the correct application name. automatically also activate the correct application name.
Edit the activate script for the shell you use. For example:
Unix Bash: ``venv/bin/activate``::
FLASK_APP=hello
export FLASK_APP
Windows CMD.exe: ``venv\Scripts\activate.bat``::
set "FLASK_APP=hello"
:END
Debug Flag Debug Flag
---------- ----------
The :command:`flask` script can be run with :option:`--debug` or :option:`--no-debug` to The :command:`flask` script can also be instructed to enable the debug
automatically flip the debug flag of the application. This can also be mode of the application automatically by exporting ``FLASK_DEBUG``. If
configured by setting ``FLASK_DEBUG`` to ``1`` or ``0``. set to ``1`` debug is enabled or ``0`` disables it::
export FLASK_DEBUG=1
Running a Shell Running a Shell
--------------- ---------------
To run an interactive Python shell you can use the ``shell`` command:: To run an interactive Python shell you can use the ``shell`` command::
flask --app=hello shell flask shell
This will start up an interactive Python shell, setup the correct This will start up an interactive Python shell, setup the correct
application context and setup the local variables in the shell. This is application context and setup the local variables in the shell. This is
@ -86,6 +97,7 @@ easily. Flask uses `click`_ for the command interface which makes
creating custom commands very easy. For instance if you want a shell creating custom commands very easy. For instance if you want a shell
command to initialize the database you can do this:: command to initialize the database you can do this::
import click
from flask import Flask from flask import Flask
app = Flask(__name__) app = Flask(__name__)
@ -93,11 +105,11 @@ command to initialize the database you can do this::
@app.cli.command() @app.cli.command()
def initdb(): def initdb():
"""Initialize the database.""" """Initialize the database."""
print 'Init the db' click.echo('Init the db')
The command will then show up on the command line:: The command will then show up on the command line::
$ flask -a hello.py initdb $ flask initdb
Init the db Init the db
Application Context Application Context
@ -122,12 +134,12 @@ Factory Functions
----------------- -----------------
In case you are using factory functions to create your application (see In case you are using factory functions to create your application (see
:ref:`app-factories`) you will discover that the :command:`flask` command cannot :ref:`app-factories`) you will discover that the :command:`flask` command
work with them directly. Flask won't be able to figure out how to cannot work with them directly. Flask won't be able to figure out how to
instantiate your application properly by itself. Because of this reason instantiate your application properly by itself. Because of this reason
the recommendation is to create a separate file that instantiates the recommendation is to create a separate file that instantiates
applications. This is by far not the only way to make this work. Another applications. This is not the only way to make this work. Another is the
is the :ref:`custom-scripts` support. :ref:`custom-scripts` support.
For instance if you have a factory function that creates an application For instance if you have a factory function that creates an application
from a filename you could make a separate file that creates such an from a filename you could make a separate file that creates such an
@ -139,8 +151,8 @@ This could be a file named :file:`autoapp.py` with these contents::
from yourapplication import create_app from yourapplication import create_app
app = create_app(os.environ['YOURAPPLICATION_CONFIG']) app = create_app(os.environ['YOURAPPLICATION_CONFIG'])
Once this has happened you can make the flask command automatically pick Once this has happened you can make the :command:`flask` command automatically
it up:: pick it up::
export YOURAPPLICATION_CONFIG=/path/to/config.cfg export YOURAPPLICATION_CONFIG=/path/to/config.cfg
export FLASK_APP=/path/to/autoapp.py export FLASK_APP=/path/to/autoapp.py
@ -152,9 +164,9 @@ From this point onwards :command:`flask` will find your application.
Custom Scripts Custom Scripts
-------------- --------------
While the most common way is to use the :command:`flask` command, you can also While the most common way is to use the :command:`flask` command, you can
make your own "driver scripts". Since Flask uses click for the scripts also make your own "driver scripts". Since Flask uses click for the
there is no reason you cannot hook these scripts into any click scripts there is no reason you cannot hook these scripts into any click
application. There is one big caveat and that is, that commands application. There is one big caveat and that is, that commands
registered to :attr:`Flask.cli` will expect to be (indirectly at least) registered to :attr:`Flask.cli` will expect to be (indirectly at least)
launched from a :class:`flask.cli.FlaskGroup` click group. This is launched from a :class:`flask.cli.FlaskGroup` click group. This is
@ -162,38 +174,32 @@ necessary so that the commands know which Flask application they have to
work with. work with.
To understand why you might want custom scripts you need to understand how To understand why you might want custom scripts you need to understand how
click finds and executes the Flask application. If you use the :command:`flask` click finds and executes the Flask application. If you use the
script you specify the application to work with on the command line or :command:`flask` script you specify the application to work with on the
environment variable as an import name. This is simple but it has some command line or environment variable as an import name. This is simple
limitations. Primarily it does not work with application factory but it has some limitations. Primarily it does not work with application
functions (see :ref:`app-factories`). factory functions (see :ref:`app-factories`).
With a custom script you don't have this problem as you can fully With a custom script you don't have this problem as you can fully
customize how the application will be created. This is very useful if you customize how the application will be created. This is very useful if you
write reusable applications that you want to ship to users and they should write reusable applications that you want to ship to users and they should
be presented with a custom management script. be presented with a custom management script.
If you are used to writing click applications this will look familiar but
at the same time, slightly different because of how commands are loaded.
We won't go into detail now about the differences but if you are curious
you can have a look at the :ref:`script-info-object` section to learn all
about it.
To explain all of this, here is an example :file:`manage.py` script that To explain all of this, here is an example :file:`manage.py` script that
manages a hypothetical wiki application. We will go through the details manages a hypothetical wiki application. We will go through the details
afterwards:: afterwards::
import os
import click import click
from flask.cli import FlaskGroup, script_info_option from flask.cli import FlaskGroup
def create_wiki_app(info): def create_wiki_app(info):
from yourwiki import create_app from yourwiki import create_app
config = info.data.get('config') or 'wikiconfig.py' return create_app(
return create_app(config=config) config=os.environ.get('WIKI_CONFIG', 'wikiconfig.py'))
@click.group(cls=FlaskGroup, create_app=create_wiki_app) @click.group(cls=FlaskGroup, create_app=create_wiki_app)
@script_info_option('--config', script_info_key='config') def cli():
def cli(**params):
"""This is a management script for the wiki application.""" """This is a management script for the wiki application."""
if __name__ == '__main__': if __name__ == '__main__':
@ -204,56 +210,51 @@ step.
1. First we import the ``click`` library as well as the click extensions 1. First we import the ``click`` library as well as the click extensions
from the ``flask.cli`` package. Primarily we are here interested from the ``flask.cli`` package. Primarily we are here interested
in the :class:`~flask.cli.FlaskGroup` click group and the in the :class:`~flask.cli.FlaskGroup` click group.
:func:`~flask.cli.script_info_option` decorator.
2. The next thing we do is defining a function that is invoked with the 2. The next thing we do is defining a function that is invoked with the
script info object (:ref:`script-info-object`) from Flask and its script info object (:class:`~flask.cli.ScriptInfo`) from Flask and its
purpose is to fully import and create the application. This can purpose is to fully import and create the application. This can
either directly import an application object or create it (see either directly import an application object or create it (see
:ref:`app-factories`). :ref:`app-factories`). In this case we load the config from an
environment variable.
What is ``info.data``? It's a dictionary of arbitrary data on the
script info that can be filled by options or through other means. We
will come back to this later.
3. Next step is to create a :class:`FlaskGroup`. In this case we just 3. Next step is to create a :class:`FlaskGroup`. In this case we just
make an empty function with a help doc string that just does nothing make an empty function with a help doc string that just does nothing
and then pass the ``create_wiki_app`` function as a factory function. and then pass the ``create_wiki_app`` function as a factory function.
Whenever click now needs to operate on a Flask application it will Whenever click now needs to operate on a Flask application it will
call that function with the script info and ask for it to be created. call that function with the script info and ask for it to be created.
4. In step 2 you could see that the config is passed to the actual 4. All is rounded up by invoking the script.
creation function. This config comes from the :func:`script_info_option`
decorator for the main script. It accepts a :option:`--config` option and CLI Plugins
then stores it in the script info so we can use it to create the -----------
application.
5. All is rounded up by invoking the script.
.. _script-info-object: Flask extensions can always patch the :attr:`Flask.cli` instance with more
commands if they want. However there is a second way to add CLI plugins
to Flask which is through ``setuptools``. If you make a Python package that
should export a Flask command line plugin you can ship a :file:`setup.py` file
that declares an entrypoint that points to a click command:
The Script Info Example :file:`setup.py`::
---------------
from setuptools import setup
setup(
name='flask-my-extension',
...
entry_points='''
[flask.commands]
my-command=mypackage.commands:cli
''',
)
Inside :file:`mypackage/commands.py` you can then export a Click object::
import click
@click.command()
def cli():
"""This is an example command."""
The Flask script integration might be confusing at first, but there is a reason Once that package is installed in the same virtualenv as Flask itself you
why it's done this way. The reason for this is that Flask wants to can run ``flask my-command`` to invoke your command. This is useful to
both provide custom commands to click as well as not loading your provide extra functionality that Flask itself cannot ship.
application unless it has to. The reason for this is added flexibility.
This way an application can provide custom commands, but even in the
absence of an application the :command:`flask` script is still operational on a
basic level. In addition to that it means that the individual commands
have the option to avoid creating an instance of the Flask application
unless required. This is very useful as it allows the server commands for
instance to load the application on a first request instead of
immediately, therefore giving a better debug experience.
All of this is provided through the :class:`flask.cli.ScriptInfo` object
and some helper utilities around. The basic way it operates is that when
the :class:`flask.cli.FlaskGroup` executes as a script it creates a script
info and keeps it around. From that point onwards modifications on the
script info can be done through click options. To simplify this pattern
the :func:`flask.cli.script_info_option` decorator was added.
Once Flask actually needs the individual Flask application it will invoke
the :meth:`flask.cli.ScriptInfo.load_app` method. This happens when the
server starts, when the shell is launched or when the script looks for an
application-provided click command.

108
docs/conf.py

@ -10,14 +10,20 @@
# #
# All configuration values have a default; values that are commented out # All configuration values have a default; values that are commented out
# serve to show the default. # serve to show the default.
from __future__ import print_function
import os
import sys
import pkg_resources
import time
import datetime
import sys, os BUILD_DATE = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.append(os.path.abspath('_themes')) sys.path.append(os.path.join(os.path.dirname(__file__), '_themes'))
sys.path.append(os.path.abspath('.')) sys.path.append(os.path.dirname(__file__))
# -- General configuration ----------------------------------------------------- # -- General configuration -----------------------------------------------------
@ -26,8 +32,11 @@ sys.path.append(os.path.abspath('.'))
# Add any Sphinx extension module names here, as strings. They can be extensions # Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', extensions = [
'flaskdocext'] 'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'flaskdocext'
]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ['_templates']
@ -43,24 +52,21 @@ master_doc = 'index'
# General information about the project. # General information about the project.
project = u'Flask' project = u'Flask'
copyright = u'2015, Armin Ronacher' copyright = u'2010 - {0}, Armin Ronacher'.format(BUILD_DATE.year)
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
# built documents. # built documents.
import pkg_resources
try: try:
release = pkg_resources.get_distribution('Flask').version release = pkg_resources.get_distribution('Flask').version
except pkg_resources.DistributionNotFound: except pkg_resources.DistributionNotFound:
print 'To build the documentation, The distribution information of Flask' print('Flask must be installed to build the documentation.')
print 'Has to be available. Either install the package into your' print('Install from source using `pip install -e .` in a virtualenv.')
print 'development environment or run "setup.py develop" to setup the'
print 'metadata. A virtualenv is recommended!'
sys.exit(1) sys.exit(1)
del pkg_resources
if 'dev' in release: if 'dev' in release:
release = release.split('dev')[0] + 'dev' release = ''.join(release.partition('dev')[:2])
version = '.'.join(release.split('.')[:2]) version = '.'.join(release.split('.')[:2])
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
@ -99,14 +105,12 @@ exclude_patterns = ['_build']
# The theme to use for HTML and HTML Help pages. Major themes that come with # The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'. # Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'flask' # html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme # Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the # further. For a list of options available for each theme, see the
# documentation. # documentation.
html_theme_options = { # html_theme_options = {}
'touch_icon': 'touch-icon.png'
}
# Add any paths that contain custom themes here, relative to this directory. # Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['_themes'] html_theme_path = ['_themes']
@ -125,7 +129,7 @@ html_theme_path = ['_themes']
# The name of an image file (within the static path) to use as favicon of the # The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large. # pixels large.
html_favicon = "flask-favicon.ico" html_favicon = '_static/flask-favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
@ -142,9 +146,18 @@ html_static_path = ['_static']
# Custom sidebar templates, maps document names to template names. # Custom sidebar templates, maps document names to template names.
html_sidebars = { html_sidebars = {
'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'], 'index': [
'**': ['sidebarlogo.html', 'localtoc.html', 'relations.html', 'sidebarintro.html',
'sourcelink.html', 'searchbox.html'] 'sourcelink.html',
'searchbox.html'
],
'**': [
'sidebarlogo.html',
'localtoc.html',
'relations.html',
'sourcelink.html',
'searchbox.html'
]
} }
# Additional templates that should be rendered to pages, maps page names to # Additional templates that should be rendered to pages, maps page names to
@ -186,8 +199,7 @@ htmlhelp_basename = 'Flaskdoc'
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]). # (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [ latex_documents = [
('latexindex', 'Flask.tex', u'Flask Documentation', ('latexindex', 'Flask.tex', u'Flask Documentation', u'Armin Ronacher', 'manual'),
u'Armin Ronacher', 'manual'),
] ]
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
@ -197,10 +209,10 @@ latex_documents = [
latex_use_modindex = False latex_use_modindex = False
latex_elements = { latex_elements = {
'fontpkg': r'\usepackage{mathpazo}', 'fontpkg': r'\usepackage{mathpazo}',
'papersize': 'a4paper', 'papersize': 'a4paper',
'pointsize': '12pt', 'pointsize': '12pt',
'preamble': r'\usepackage{flaskstyle}' 'preamble': r'\usepackage{flaskstyle}'
} }
latex_use_parts = True latex_use_parts = True
@ -222,7 +234,7 @@ latex_additional_files = ['flaskstyle.sty', 'logo.pdf']
# The scheme of the identifier. Typical schemes are ISBN or URL. # The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = '' #epub_scheme = ''
# The unique identifier of the text. This can be a ISBN number # The unique identifier of the text. This can be an ISBN number
# or the project homepage. # or the project homepage.
#epub_identifier = '' #epub_identifier = ''
@ -244,31 +256,29 @@ latex_additional_files = ['flaskstyle.sty', 'logo.pdf']
#epub_tocdepth = 3 #epub_tocdepth = 3
intersphinx_mapping = { intersphinx_mapping = {
'https://docs.python.org/dev': None, 'python': ('https://docs.python.org/3/', None),
'http://werkzeug.pocoo.org/docs/': None, 'werkzeug': ('http://werkzeug.pocoo.org/docs/', None),
'http://click.pocoo.org/': None, 'click': ('http://click.pocoo.org/', None),
'http://jinja.pocoo.org/docs/': None, 'jinja': ('http://jinja.pocoo.org/docs/', None),
'http://www.sqlalchemy.org/docs/': None, 'sqlalchemy': ('https://docs.sqlalchemy.org/en/latest/', None),
'https://wtforms.readthedocs.org/en/latest/': None, 'wtforms': ('https://wtforms.readthedocs.io/en/latest/', None),
'https://pythonhosted.org/blinker/': None 'blinker': ('https://pythonhosted.org/blinker/', None)
} }
pygments_style = 'flask_theme_support.FlaskyStyle'
# fall back if theme is not there
try: try:
__import__('flask_theme_support') __import__('flask_theme_support')
except ImportError, e: pygments_style = 'flask_theme_support.FlaskyStyle'
print '-' * 74 html_theme = 'flask'
print 'Warning: Flask themes unavailable. Building with default theme' html_theme_options = {
print 'If you want the Flask themes, run this command and build again:' 'touch_icon': 'touch-icon.png'
print }
print ' git submodule update --init' except ImportError:
print '-' * 74 print('-' * 74)
print('Warning: Flask themes unavailable. Building with default theme')
pygments_style = 'tango' print('If you want the Flask themes, run this command and build again:')
html_theme = 'default' print()
html_theme_options = {} print(' git submodule update --init')
print('-' * 74)
# unwrap decorators # unwrap decorators

36
docs/config.rst

@ -44,6 +44,21 @@ method::
SECRET_KEY='...' SECRET_KEY='...'
) )
.. admonition:: Debug Mode with the ``flask`` Script
If you use the :command:`flask` script to start a local development
server, to enable the debug mode, you need to export the ``FLASK_DEBUG``
environment variable before running the server::
$ export FLASK_DEBUG=1
$ flask run
(On Windows you need to use ``set`` instead of ``export``).
``app.debug`` and ``app.config['DEBUG']`` are not compatible with
  the :command:`flask` script. They only worked when using ``Flask.run()``
method.
Builtin Configuration Values Builtin Configuration Values
---------------------------- ----------------------------
@ -52,7 +67,8 @@ The following configuration values are used internally by Flask:
.. tabularcolumns:: |p{6.5cm}|p{8.5cm}| .. tabularcolumns:: |p{6.5cm}|p{8.5cm}|
================================= ========================================= ================================= =========================================
``DEBUG`` enable/disable debug mode ``DEBUG`` enable/disable debug mode when using
``Flask.run()`` method to start server
``TESTING`` enable/disable testing mode ``TESTING`` enable/disable testing mode
``PROPAGATE_EXCEPTIONS`` explicitly enable or disable the ``PROPAGATE_EXCEPTIONS`` explicitly enable or disable the
propagation of exceptions. If not set or propagation of exceptions. If not set or
@ -177,12 +193,11 @@ The following configuration values are used internally by Flask:
behavior by changing this variable. behavior by changing this variable.
This is not recommended but might give This is not recommended but might give
you a performance improvement on the you a performance improvement on the
cost of cachability. cost of cacheability.
``JSONIFY_PRETTYPRINT_REGULAR`` If this is set to ``True`` (the default) ``JSONIFY_PRETTYPRINT_REGULAR`` If this is set to ``True`` or the Flask app
jsonify responses will be pretty printed is running in debug mode, jsonify responses
if they are not requested by an will be pretty printed.
XMLHttpRequest object (controlled by ``JSONIFY_MIMETYPE`` MIME type used for jsonify responses.
the ``X-Requested-With`` header)
``TEMPLATES_AUTO_RELOAD`` Whether to check for modifications of ``TEMPLATES_AUTO_RELOAD`` Whether to check for modifications of
the template source and reload it the template source and reload it
automatically. By default the value is automatically. By default the value is
@ -240,7 +255,7 @@ The following configuration values are used internally by Flask:
.. versionadded:: 0.10 .. versionadded:: 0.10
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_PRETTYPRINT_REGULAR`` ``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_PRETTYPRINT_REGULAR``
.. versionadded:: 1.0 .. versionadded:: 0.11
``SESSION_REFRESH_EACH_REQUEST``, ``TEMPLATES_AUTO_RELOAD``, ``SESSION_REFRESH_EACH_REQUEST``, ``TEMPLATES_AUTO_RELOAD``,
``LOGGER_HANDLER_POLICY``, ``EXPLAIN_TEMPLATE_LOADING`` ``LOGGER_HANDLER_POLICY``, ``EXPLAIN_TEMPLATE_LOADING``
@ -261,7 +276,7 @@ So a common pattern is this::
This first loads the configuration from the This first loads the configuration from the
`yourapplication.default_settings` module and then overrides the values `yourapplication.default_settings` module and then overrides the values
with the contents of the file the :envvar:``YOURAPPLICATION_SETTINGS`` with the contents of the file the :envvar:`YOURAPPLICATION_SETTINGS`
environment variable points to. This environment variable can be set on environment variable points to. This environment variable can be set on
Linux or OS X with the export command in the shell before starting the Linux or OS X with the export command in the shell before starting the
server:: server::
@ -309,6 +324,7 @@ that experience:
limit yourself to request-only accesses to the configuration you can limit yourself to request-only accesses to the configuration you can
reconfigure the object later on as needed. reconfigure the object later on as needed.
.. _config-dev-prod:
Development / Production Development / Production
------------------------ ------------------------
@ -330,7 +346,7 @@ there are alternative ways as well. For example you could use imports or
subclassing. subclassing.
What is very popular in the Django world is to make the import explicit in What is very popular in the Django world is to make the import explicit in
the config file by adding an ``from yourapplication.default_settings the config file by adding ``from yourapplication.default_settings
import *`` to the top of the file and then overriding the changes by hand. import *`` to the top of the file and then overriding the changes by hand.
You could also inspect an environment variable like You could also inspect an environment variable like
``YOURAPPLICATION_MODE`` and set that to `production`, `development` etc ``YOURAPPLICATION_MODE`` and set that to `production`, `development` etc

8
docs/deploying/fastcgi.rst

@ -144,7 +144,7 @@ A basic FastCGI configuration for lighttpd looks like that::
) )
alias.url = ( alias.url = (
"/static/" => "/path/to/your/static" "/static/" => "/path/to/your/static/"
) )
url.rewrite-once = ( url.rewrite-once = (
@ -159,7 +159,7 @@ work in the URL root you have to work around a lighttpd bug with the
Make sure to apply it only if you are mounting the application the URL Make sure to apply it only if you are mounting the application the URL
root. Also, see the Lighty docs for more information on `FastCGI and Python root. Also, see the Lighty docs for more information on `FastCGI and Python
<http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModFastCGI>`_ (note that <https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModFastCGI>`_ (note that
explicitly passing a socket to run() is no longer necessary). explicitly passing a socket to run() is no longer necessary).
Configuring nginx Configuring nginx
@ -234,7 +234,7 @@ python path. Common problems are:
web server. web server.
- Different python interpreters being used. - Different python interpreters being used.
.. _nginx: http://nginx.org/ .. _nginx: https://nginx.org/
.. _lighttpd: http://www.lighttpd.net/ .. _lighttpd: https://www.lighttpd.net/
.. _cherokee: http://cherokee-project.com/ .. _cherokee: http://cherokee-project.com/
.. _flup: https://pypi.python.org/pypi/flup .. _flup: https://pypi.python.org/pypi/flup

4
docs/deploying/index.rst

@ -19,12 +19,12 @@ Hosted options
- `Deploying Flask on Heroku <https://devcenter.heroku.com/articles/getting-started-with-python>`_ - `Deploying Flask on Heroku <https://devcenter.heroku.com/articles/getting-started-with-python>`_
- `Deploying Flask on OpenShift <https://developers.openshift.com/en/python-flask.html>`_ - `Deploying Flask on OpenShift <https://developers.openshift.com/en/python-flask.html>`_
- `Deploying WSGI on dotCloud <http://docs.dotcloud.com/services/python/>`_
with `Flask-specific notes <http://flask.pocoo.org/snippets/48/>`_
- `Deploying Flask on Webfaction <http://flask.pocoo.org/snippets/65/>`_ - `Deploying Flask on Webfaction <http://flask.pocoo.org/snippets/65/>`_
- `Deploying Flask on Google App Engine <https://github.com/kamalgill/flask-appengine-template>`_ - `Deploying Flask on Google App Engine <https://github.com/kamalgill/flask-appengine-template>`_
- `Deploying Flask on AWS Elastic Beanstalk <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-flask.html>`_
- `Sharing your Localhost Server with Localtunnel <http://flask.pocoo.org/snippets/89/>`_ - `Sharing your Localhost Server with Localtunnel <http://flask.pocoo.org/snippets/89/>`_
- `Deploying on Azure (IIS) <https://azure.microsoft.com/documentation/articles/web-sites-python-configure/>`_ - `Deploying on Azure (IIS) <https://azure.microsoft.com/documentation/articles/web-sites-python-configure/>`_
- `Deploying on PythonAnywhere <https://help.pythonanywhere.com/pages/Flask/>`_
Self-hosted options Self-hosted options
------------------- -------------------

14
docs/deploying/mod_wsgi.rst

@ -13,7 +13,7 @@ If you are using the `Apache`_ webserver, consider using `mod_wsgi`_.
not called because this will always start a local WSGI server which not called because this will always start a local WSGI server which
we do not want if we deploy that application to mod_wsgi. we do not want if we deploy that application to mod_wsgi.
.. _Apache: http://httpd.apache.org/ .. _Apache: https://httpd.apache.org/
Installing `mod_wsgi` Installing `mod_wsgi`
--------------------- ---------------------
@ -114,7 +114,7 @@ refuse to run with the above configuration. On a Windows system, eliminate those
Note: There have been some changes in access control configuration for `Apache 2.4`_. Note: There have been some changes in access control configuration for `Apache 2.4`_.
.. _Apache 2.4: http://httpd.apache.org/docs/trunk/upgrading.html .. _Apache 2.4: https://httpd.apache.org/docs/trunk/upgrading.html
Most notably, the syntax for directory permissions has changed from httpd 2.2 Most notably, the syntax for directory permissions has changed from httpd 2.2
@ -130,12 +130,12 @@ to httpd 2.4 syntax
Require all granted Require all granted
For more information consult the `mod_wsgi wiki`_. For more information consult the `mod_wsgi documentation`_.
.. _mod_wsgi: http://code.google.com/p/modwsgi/ .. _mod_wsgi: https://github.com/GrahamDumpleton/mod_wsgi
.. _installation instructions: http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide .. _installation instructions: https://modwsgi.readthedocs.io/en/develop/installation.html
.. _virtual python: https://pypi.python.org/pypi/virtualenv .. _virtual python: https://pypi.python.org/pypi/virtualenv
.. _mod_wsgi wiki: http://code.google.com/p/modwsgi/w/list .. _mod_wsgi documentation: https://modwsgi.readthedocs.io/en/develop/index.html
Troubleshooting Troubleshooting
--------------- ---------------
@ -143,7 +143,7 @@ Troubleshooting
If your application does not run, follow this guide to troubleshoot: If your application does not run, follow this guide to troubleshoot:
**Problem:** application does not run, errorlog shows SystemExit ignored **Problem:** application does not run, errorlog shows SystemExit ignored
You have a ``app.run()`` call in your application file that is not You have an ``app.run()`` call in your application file that is not
guarded by an ``if __name__ == '__main__':`` condition. Either guarded by an ``if __name__ == '__main__':`` condition. Either
remove that :meth:`~flask.Flask.run` call from the file and move it remove that :meth:`~flask.Flask.run` call from the file and move it
into a separate :file:`run.py` file or put it into such an if block. into a separate :file:`run.py` file or put it into such an if block.

26
docs/deploying/uwsgi.rst

@ -29,20 +29,16 @@ Given a flask application in myapp.py, use the following command:
.. sourcecode:: text .. sourcecode:: text
$ uwsgi -s /tmp/uwsgi.sock --manage-script-name --mount /yourapplication=myapp:app $ uwsgi -s /tmp/yourapplication.sock --manage-script-name --mount /yourapplication=myapp:app
Or, if you prefer: The ``--manage-script-name`` will move the handling of ``SCRIPT_NAME`` to uwsgi,
since its smarter about that. It is used together with the ``--mount`` directive
.. sourcecode:: text which will make requests to ``/yourapplication`` be directed to ``myapp:app``.
If your application is accessible at root level, you can use a single ``/``
$ uwsgi -s /tmp/uwsgi.sock --manage-script-name --mount /yourapplication=myapp:app instead of ``/yourapplication``. ``myapp`` refers to the name of the file of
your flask application (without extension) or the module which provides ``app``.
The ``--manage-script-name`` will move the handling of ``SCRIPT_NAME`` to ``app`` is the callable inside of your application (usually the line reads
uwsgi, since its smarter about that. It is used together with the ``--mount`` ``app = Flask(__name__)``.
directive which will make requests to ``/yourapplication`` be directed to
``myapp:app``, where ``myapp`` refers to the name of the file of your flask
application (without extension). ``app`` is the callable inside of your
application (usually the line reads ``app = Flask(__name__)``.
If you want to deploy your flask application inside of a virtual environment, If you want to deploy your flask application inside of a virtual environment,
you need to also add ``--virtualenv /path/to/virtual/environment``. You might you need to also add ``--virtualenv /path/to/virtual/environment``. You might
@ -70,7 +66,7 @@ to have it in the URL root its a bit simpler::
uwsgi_pass unix:/tmp/yourapplication.sock; uwsgi_pass unix:/tmp/yourapplication.sock;
} }
.. _nginx: http://nginx.org/ .. _nginx: https://nginx.org/
.. _lighttpd: http://www.lighttpd.net/ .. _lighttpd: https://www.lighttpd.net/
.. _cherokee: http://cherokee-project.com/ .. _cherokee: http://cherokee-project.com/
.. _uwsgi: http://projects.unbit.it/uwsgi/ .. _uwsgi: http://projects.unbit.it/uwsgi/

11
docs/deploying/wsgi-standalone.rst

@ -25,7 +25,7 @@ For example, to run a Flask application with 4 worker processes (``-w
.. _Gunicorn: http://gunicorn.org/ .. _Gunicorn: http://gunicorn.org/
.. _eventlet: http://eventlet.net/ .. _eventlet: http://eventlet.net/
.. _greenlet: http://greenlet.readthedocs.org/en/latest/ .. _greenlet: https://greenlet.readthedocs.io/en/latest/
Gevent Gevent
------- -------
@ -41,7 +41,7 @@ event loop::
http_server.serve_forever() http_server.serve_forever()
.. _Gevent: http://www.gevent.org/ .. _Gevent: http://www.gevent.org/
.. _greenlet: http://greenlet.readthedocs.org/en/latest/ .. _greenlet: https://greenlet.readthedocs.io/en/latest/
.. _libev: http://software.schmorp.de/pkg/libev.html .. _libev: http://software.schmorp.de/pkg/libev.html
Twisted Web Twisted Web
@ -97,9 +97,10 @@ localhost at port 8000, setting appropriate headers:
proxy_pass http://127.0.0.1:8000/; proxy_pass http://127.0.0.1:8000/;
proxy_redirect off; proxy_redirect off;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
} }
} }

68
docs/errorhandling.rst

@ -28,6 +28,46 @@ exception to the :attr:`~flask.Flask.logger`.
But there is more you can do, and we will cover some better setups to deal But there is more you can do, and we will cover some better setups to deal
with errors. with errors.
Error Logging Tools
-------------------
Sending error mails, even if just for critical ones, can become
overwhelming if enough users are hitting the error and log files are
typically never looked at. This is why we recommend using `Sentry
<https://www.getsentry.com/>`_ for dealing with application errors. It's
available as an Open Source project `on GitHub
<https://github.com/getsentry/sentry>`__ and is also available as a `hosted version
<https://getsentry.com/signup/>`_ which you can try for free. Sentry
aggregates duplicate errors, captures the full stack trace and local
variables for debugging, and sends you mails based on new errors or
frequency thresholds.
To use Sentry you need to install the `raven` client::
$ pip install raven
And then add this to your Flask app::
from raven.contrib.flask import Sentry
sentry = Sentry(app, dsn='YOUR_DSN_HERE')
Or if you are using factories you can also init it later::
from raven.contrib.flask import Sentry
sentry = Sentry(dsn='YOUR_DSN_HERE')
def create_app():
app = Flask(__name__)
sentry.init_app(app)
...
return app
The `YOUR_DSN_HERE` value needs to be replaced with the DSN value you get
from your Sentry installation.
Afterwards failures are automatically reported to Sentry and from there
you can receive error notifications.
.. _error-handlers: .. _error-handlers:
Error handlers Error handlers
@ -37,7 +77,7 @@ You might want to show custom error pages to the user when an error occurs.
This can be done by registering error handlers. This can be done by registering error handlers.
Error handlers are normal :ref:`views` but instead of being registered for Error handlers are normal :ref:`views` but instead of being registered for
routes they are registered for exceptions that are rised while trying to routes, they are registered for exceptions that are raised while trying to
do something else. do something else.
Registering Registering
@ -49,23 +89,24 @@ Register error handlers using :meth:`~flask.Flask.errorhandler` or
@app.errorhandler(werkzeug.exceptions.BadRequest) @app.errorhandler(werkzeug.exceptions.BadRequest)
def handle_bad_request(e): def handle_bad_request(e):
return 'bad request!' return 'bad request!'
app.register_error_handler(400, lambda e: 'bad request!') app.register_error_handler(400, lambda e: 'bad request!')
Those two ways are equivalent, but the first one is more clear and leaves Those two ways are equivalent, but the first one is more clear and leaves
you with a function to call on your whim (and in tests). Note that you with a function to call on your whim (and in tests). Note that
:exc:`werkzeug.exceptions.HTTPException` subclasses like :exc:`werkzeug.exceptions.HTTPException` subclasses like
:exc:`~werkzeug.exceptions.BadRequest` from the example and their HTTP codes :exc:`~werkzeug.exceptions.BadRequest` from the example and their HTTP codes
are interchangable when handed to the registration methods or decorator are interchangeable when handed to the registration methods or decorator
(``BadRequest.code == 400``). (``BadRequest.code == 400``).
You are however not limited to a :exc:`~werkzeug.exceptions.HTTPException` You are however not limited to :exc:`~werkzeug.exceptions.HTTPException`
or its code but can register a handler for every exception class you like. or HTTP status codes but can register a handler for every exception class you
like.
.. versionchanged:: 1.0 .. versionchanged:: 0.11
Errorhandlers are now prioritized by specifity instead of the order they're Errorhandlers are now prioritized by specificity of the exception classes
registered in. they are registered for instead of the order they are registered in.
Handling Handling
```````` ````````
@ -74,7 +115,7 @@ Once an exception instance is raised, its class hierarchy is traversed,
and searched for in the exception classes for which handlers are registered. and searched for in the exception classes for which handlers are registered.
The most specific handler is selected. The most specific handler is selected.
E.g. if a instance of :exc:`ConnectionRefusedError` is raised, and a handler E.g. if an instance of :exc:`ConnectionRefusedError` is raised, and a handler
is registered for :exc:`ConnectionError` and :exc:`ConnectionRefusedError`, is registered for :exc:`ConnectionError` and :exc:`ConnectionRefusedError`,
the more specific :exc:`ConnectionRefusedError` handler is called on the the more specific :exc:`ConnectionRefusedError` handler is called on the
exception instance, and its response is shown to the user. exception instance, and its response is shown to the user.
@ -130,7 +171,7 @@ Logging to a File
Even if you get mails, you probably also want to log warnings. It's a Even if you get mails, you probably also want to log warnings. It's a
good idea to keep as much information around that might be required to good idea to keep as much information around that might be required to
debug a problem. By default as of Flask 1.0, errors are logged to your debug a problem. By default as of Flask 0.11, errors are logged to your
webserver's log automatically. Warnings however are not. Please note webserver's log automatically. Warnings however are not. Please note
that Flask itself will not issue any warnings in the core system, so it's that Flask itself will not issue any warnings in the core system, so it's
your responsibility to warn in the code if something seems odd. your responsibility to warn in the code if something seems odd.
@ -175,7 +216,7 @@ A formatter can be instantiated with a format string. Note that
tracebacks are appended to the log entry automatically. You don't have to tracebacks are appended to the log entry automatically. You don't have to
do that in the log formatter format string. do that in the log formatter format string.
Here some example setups: Here are some example setups:
Email Email
````` `````
@ -235,8 +276,9 @@ that this list is not complete, consult the official documentation of the
| ``%(lineno)d`` | Source line number where the logging call was | | ``%(lineno)d`` | Source line number where the logging call was |
| | issued (if available). | | | issued (if available). |
+------------------+----------------------------------------------------+ +------------------+----------------------------------------------------+
| ``%(asctime)s`` | Human-readable time when the LogRecord` was | | ``%(asctime)s`` | Human-readable time when the |
| | created. By default this is of the form | | | :class:`~logging.LogRecord` was created. |
| | By default this is of the form |
| | ``"2003-07-08 16:49:45,896"`` (the numbers after | | | ``"2003-07-08 16:49:45,896"`` (the numbers after |
| | the comma are millisecond portion of the time). | | | the comma are millisecond portion of the time). |
| | This can be changed by subclassing the formatter | | | This can be changed by subclassing the formatter |

38
docs/extensiondev.rst

@ -29,13 +29,7 @@ be something like "Flask-SimpleXML". Make sure to include the name
This is how users can then register dependencies to your extension in This is how users can then register dependencies to your extension in
their :file:`setup.py` files. their :file:`setup.py` files.
Flask sets up a redirect package called :data:`flask.ext` where users But what do extensions look like themselves? An extension has to ensure
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 that it works with multiple Flask application instances at once. This is
a requirement because many people will use patterns like the a requirement because many people will use patterns like the
:ref:`app-factories` pattern to create their application as needed to aid :ref:`app-factories` pattern to create their application as needed to aid
@ -360,8 +354,7 @@ extension to be approved you have to follow these guidelines:
find a new maintainer including full source hosting transition and PyPI find a new maintainer including full source hosting transition and PyPI
access. If no maintainer is available, give access to the Flask core team. access. If no maintainer is available, give access to the Flask core team.
1. An approved Flask extension must provide exactly one package or module 1. An approved Flask extension must provide exactly one package or module
named ``flask_extensionname``. They might also reside inside a named ``flask_extensionname``.
``flaskext`` namespace packages though this is discouraged now.
2. It must ship a testing suite that can either be invoked with ``make test`` 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 or ``python setup.py test``. For test suites invoked with ``make
test`` the extension has to ensure that all dependencies for the test test`` the extension has to ensure that all dependencies for the test
@ -394,27 +387,24 @@ extension to be approved you have to follow these guidelines:
Python 2.7 Python 2.7
.. _ext-import-transition:
Extension Import Transition Extension Import Transition
--------------------------- ---------------------------
For a while we recommended using namespace packages for Flask extensions. In early versions of Flask we recommended using namespace packages for Flask
This turned out to be problematic in practice because many different extensions, of the form ``flaskext.foo``. This turned out to be problematic in
competing namespace package systems exist and pip would automatically practice because it meant that multiple ``flaskext`` packages coexist.
switch between different systems and this caused a lot of problems for Consequently we have recommended to name extensions ``flask_foo`` over
users. ``flaskext.foo`` for a long time.
Instead we now recommend naming packages ``flask_foo`` instead of the now Flask 0.8 introduced a redirect import system as a compatibility aid for app
deprecated ``flaskext.foo``. Flask 0.8 introduces a redirect import developers: Importing ``flask.ext.foo`` would try ``flask_foo`` and
system that lets uses import from ``flask.ext.foo`` and it will try ``flaskext.foo`` in that order.
``flask_foo`` first and if that fails ``flaskext.foo``.
Flask extensions should urge users to import from ``flask.ext.foo`` As of Flask 0.11, most Flask extensions have transitioned to the new naming
instead of ``flask_foo`` or ``flaskext_foo`` so that extensions can schema. The ``flask.ext.foo`` compatibility alias is still in Flask 0.11 but is
transition to the new package name without affecting users. now deprecated -- you should use ``flask_foo``.
.. _OAuth extension: http://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/

18
docs/extensions.rst

@ -1,3 +1,5 @@
.. _extensions:
Flask Extensions Flask Extensions
================ ================
@ -18,10 +20,17 @@ Using Extensions
Extensions typically have documentation that goes along that shows how to Extensions typically have documentation that goes along that shows how to
use it. There are no general rules in how extensions are supposed to use it. There are no general rules in how extensions are supposed to
behave but they are imported from common locations. If you have an behave but they are imported from common locations. If you have an
extension called ``Flask-Foo`` or ``Foo-Flask`` it will be always extension called ``Flask-Foo`` or ``Foo-Flask`` it should be always
importable from ``flask.ext.foo``:: importable from ``flask_foo``::
from flask.ext import foo import flask_foo
Building Extensions
-------------------
While `Flask Extension Registry`_ contains many Flask extensions, you may not find
an extension that fits your need. If this is the case, you can always create your own.
Consider reading :ref:`extension-dev` to develop your own Flask extension.
Flask Before 0.8 Flask Before 0.8
---------------- ----------------
@ -44,5 +53,6 @@ And here is how you can use it::
Once the ``flaskext_compat`` module is activated the :data:`flask.ext` will Once the ``flaskext_compat`` module is activated the :data:`flask.ext` will
exist and you can start importing from there. exist and you can start importing from there.
.. _Flask Extension Registry: http://flask.pocoo.org/extensions/ .. _Flask Extension Registry: http://flask.pocoo.org/extensions/
.. _flaskext_compat.py: https://raw.githubusercontent.com/mitsuhiko/flask/master/scripts/flaskext_compat.py .. _flaskext_compat.py: https://raw.githubusercontent.com/pallets/flask/master/scripts/flaskext_compat.py

2
docs/htmlfaq.rst

@ -30,7 +30,7 @@ the (X)HTML generation on the web is based on non-XML template engines
(such as Jinja, the one used in Flask) which do not protect you from (such as Jinja, the one used in Flask) which do not protect you from
accidentally creating invalid XHTML. There are XML based template engines, accidentally creating invalid XHTML. There are XML based template engines,
such as Kid and the popular Genshi, but they often come with a larger such as Kid and the popular Genshi, but they often come with a larger
runtime overhead and, are not as straightforward to use because they have runtime overhead and are not as straightforward to use because they have
to obey XML rules. to obey XML rules.
The majority of users, however, assumed they were properly using XHTML. The majority of users, however, assumed they were properly using XHTML.

55
docs/installation.rst

@ -40,24 +40,20 @@ installations of Python, one for each project. It doesn't actually install
separate copies of Python, but it does provide a clever way to keep different separate copies of Python, but it does provide a clever way to keep different
project environments isolated. Let's see how virtualenv works. project environments isolated. Let's see how virtualenv works.
If you are on Mac OS X or Linux, chances are that one of the following two If you are on Mac OS X or Linux, chances are that the following
commands will work for you:: command will work for you::
$ sudo easy_install virtualenv
or even better::
$ sudo pip install virtualenv $ sudo pip install virtualenv
One of these will probably install virtualenv on your system. Maybe it's even It will probably install virtualenv on your system. Maybe it's even
in your package manager. If you use Ubuntu, try:: in your package manager. If you use Ubuntu, try::
$ sudo apt-get install python-virtualenv $ sudo apt-get install python-virtualenv
If you are on Windows and don't have the :command:`easy_install` command, you must If you are on Windows and don't have the ``easy_install`` command, you must
install it first. Check the :ref:`windows-easy-install` section for more install it first. Check the :ref:`windows-easy-install` section for more
information about how to do that. Once you have it installed, run the same information about how to do that. Once you have it installed, run the same
commands as above, but without the :command:`sudo` prefix. commands as above, but without the ``sudo`` prefix.
Once you have virtualenv installed, just fire up a shell and create Once you have virtualenv installed, just fire up a shell and create
your own environment. I usually create a project folder and a :file:`venv` your own environment. I usually create a project folder and a :file:`venv`
@ -76,7 +72,7 @@ corresponding environment. On OS X and Linux, do the following::
If you are a Windows user, the following command is for you:: If you are a Windows user, the following command is for you::
$ venv\scripts\activate $ venv\Scripts\activate
Either way, you should now be using your virtualenv (notice how the prompt of Either way, you should now be using your virtualenv (notice how the prompt of
your shell has changed to show the active environment). your shell has changed to show the active environment).
@ -99,24 +95,24 @@ System-Wide Installation
------------------------ ------------------------
This is possible as well, though I do not recommend it. Just run This is possible as well, though I do not recommend it. Just run
:command:`pip` with root privileges:: ``pip`` with root privileges::
$ sudo pip install Flask $ sudo pip install Flask
(On Windows systems, run it in a command-prompt window with administrator (On Windows systems, run it in a command-prompt window with administrator
privileges, and leave out :command:`sudo`.) privileges, and leave out ``sudo``.)
Living on the Edge Living on the Edge
------------------ ------------------
If you want to work with the latest version of Flask, there are two ways: you If you want to work with the latest version of Flask, there are two ways: you
can either let :command:`pip` pull in the development version, or you can tell can either let ``pip`` pull in the development version, or you can tell
it to operate on a git checkout. Either way, virtualenv is recommended. it to operate on a git checkout. Either way, virtualenv is recommended.
Get the git checkout in a new virtualenv and run in development mode:: Get the git checkout in a new virtualenv and run in development mode::
$ git clone http://github.com/mitsuhiko/flask.git $ git clone https://github.com/pallets/flask.git
Initialized empty Git repository in ~/dev/flask/.git/ Initialized empty Git repository in ~/dev/flask/.git/
$ cd flask $ cd flask
$ virtualenv venv $ virtualenv venv
@ -131,40 +127,34 @@ This will pull in the dependencies and activate the git head as the current
version inside the virtualenv. Then all you have to do is run ``git pull version inside the virtualenv. Then all you have to do is run ``git pull
origin`` to update to the latest version. origin`` to update to the latest version.
.. _windows-easy-install: .. _windows-easy-install:
`pip` and `setuptools` on Windows `pip` and `setuptools` on Windows
--------------------------------- ---------------------------------
Sometimes getting the standard "Python packaging tools" like *pip*, *setuptools* Sometimes getting the standard "Python packaging tools" like ``pip``, ``setuptools``
and *virtualenv* can be a little trickier, but nothing very hard. The two crucial and ``virtualenv`` can be a little trickier, but nothing very hard. The crucial
packages you will need are setuptools and pip - these will let you install package you will need is pip - this will let you install
anything else (like virtualenv). Fortunately there are two "bootstrap scripts" anything else (like virtualenv). Fortunately there is a "bootstrap script"
you can run to install either. you can run to install.
If you don't currently have either, then `get-pip.py` will install both for you If you don't currently have ``pip``, then `get-pip.py` will install it for you.
(you won't need to run ez_setup.py).
`get-pip.py`_ `get-pip.py`_
To install the latest setuptools, you can use its bootstrap file: It should be double-clickable once you download it. If you already have ``pip``,
`ez_setup.py`_
Either should be double-clickable once you download them. If you already have pip,
you can upgrade them by running:: you can upgrade them by running::
> pip install --upgrade pip setuptools > pip install --upgrade pip setuptools
Most often, once you pull up a command prompt you want to be able to type :command:`pip` Most often, once you pull up a command prompt you want to be able to type ``pip``
and :command:`python` which will run those things, but this might not automatically happen and ``python`` which will run those things, but this might not automatically happen
on Windows, because it doesn't know where those executables are (give either a try!). on Windows, because it doesn't know where those executables are (give either a try!).
To fix this, you should be able to navigate to your Python install directory To fix this, you should be able to navigate to your Python install directory
(e.g :file:`C:\Python27`), then go to :file:`Tools`, then :file:`Scripts`; then find the (e.g :file:`C:\Python27`), then go to :file:`Tools`, then :file:`Scripts`, then find the
:file:`win_add2path.py` file and run that. Open a **new** Command Prompt and :file:`win_add2path.py` file and run that. Open a **new** Command Prompt and
check that you can now just type :command:`python` to bring up the interpreter. check that you can now just type ``python`` to bring up the interpreter.
Finally, to install `virtualenv`_, you can simply run:: Finally, to install `virtualenv`_, you can simply run::
@ -172,5 +162,4 @@ Finally, to install `virtualenv`_, you can simply run::
Then you can be off on your way following the installation instructions above. Then you can be off on your way following the installation instructions above.
.. _get-pip.py: https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py .. _get-pip.py: https://bootstrap.pypa.io/get-pip.py
.. _ez_setup.py: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py

2
docs/patterns/apierrors.rst

@ -2,7 +2,7 @@ Implementing API Exceptions
=========================== ===========================
It's very common to implement RESTful APIs on top of Flask. One of the It's very common to implement RESTful APIs on top of Flask. One of the
first thing that developers run into is the realization that the builtin first things that developers run into is the realization that the builtin
exceptions are not expressive enough for APIs and that the content type of exceptions are not expressive enough for APIs and that the content type of
:mimetype:`text/html` they are emitting is not very useful for API consumers. :mimetype:`text/html` they are emitting is not very useful for API consumers.

14
docs/patterns/appdispatch.rst

@ -4,11 +4,11 @@ Application Dispatching
======================= =======================
Application dispatching is the process of combining multiple Flask Application dispatching is the process of combining multiple Flask
applications on the WSGI level. You can not only combine Flask applications on the WSGI level. You can combine not only Flask
applications into something larger but any WSGI application. This would applications but any WSGI application. This would allow you to run a
even allow you to run a Django and a Flask application in the same Django and a Flask application in the same interpreter side by side if
interpreter side by side if you want. The usefulness of this depends on you want. The usefulness of this depends on how the applications work
how the applications work internally. internally.
The fundamental difference from the :ref:`module approach The fundamental difference from the :ref:`module approach
<larger-applications>` is that in this case you are running the same or <larger-applications>` is that in this case you are running the same or
@ -31,7 +31,7 @@ Note that :func:`run_simple <werkzeug.serving.run_simple>` is not intended for
use in production. Use a :ref:`full-blown WSGI server <deployment>`. use in production. Use a :ref:`full-blown WSGI server <deployment>`.
In order to use the interactive debugger, debugging must be enabled both on In order to use the interactive debugger, debugging must be enabled both on
the application and the simple server, here is the "hello world" example with the application and the simple server. Here is the "hello world" example with
debugging and :func:`run_simple <werkzeug.serving.run_simple>`:: debugging and :func:`run_simple <werkzeug.serving.run_simple>`::
from flask import Flask from flask import Flask
@ -56,7 +56,7 @@ If you have entirely separated applications and you want them to work next
to each other in the same Python interpreter process you can take to each other in the same Python interpreter process you can take
advantage of the :class:`werkzeug.wsgi.DispatcherMiddleware`. The idea advantage of the :class:`werkzeug.wsgi.DispatcherMiddleware`. The idea
here is that each Flask application is a valid WSGI application and they here is that each Flask application is a valid WSGI application and they
are combined by the dispatcher middleware into a larger one that are combined by the dispatcher middleware into a larger one that is
dispatched based on prefix. dispatched based on prefix.
For example you could have your main application run on ``/`` and your For example you could have your main application run on ``/`` and your

7
docs/patterns/appfactories.rst

@ -6,7 +6,7 @@ Application Factories
If you are already using packages and blueprints for your application If you are already using packages and blueprints for your application
(:ref:`blueprints`) there are a couple of really nice ways to further improve (:ref:`blueprints`) there are a couple of really nice ways to further improve
the experience. A common pattern is creating the application object when the experience. A common pattern is creating the application object when
the blueprint is imported. But if you move the creation of this object, the blueprint is imported. But if you move the creation of this object
into a function, you can then create multiple instances of this app later. into a function, you can then create multiple instances of this app later.
So why would you want to do this? So why would you want to do this?
@ -60,7 +60,7 @@ Factories & Extensions
It's preferable to create your extensions and app factories so that the It's preferable to create your extensions and app factories so that the
extension object does not initially get bound to the application. extension object does not initially get bound to the application.
Using `Flask-SQLAlchemy <http://pythonhosted.org/Flask-SQLAlchemy/>`_, Using `Flask-SQLAlchemy <http://flask-sqlalchemy.pocoo.org/>`_,
as an example, you should not do something along those lines:: as an example, you should not do something along those lines::
def create_app(config_filename): def create_app(config_filename):
@ -99,7 +99,8 @@ an application::
It can then be used with the :command:`flask` command:: It can then be used with the :command:`flask` command::
flask --app=exampleapp run export FLASK_APP=exampleapp
flask run
Factory Improvements Factory Improvements
-------------------- --------------------

2
docs/patterns/celery.rst

@ -36,7 +36,7 @@ This is all that is necessary to properly integrate Celery with Flask::
from celery import Celery from celery import Celery
def make_celery(app): def make_celery(app):
celery = Celery(app.import_name, backend=app.config['CELERY_BACKEND'], celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']) broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config) celery.conf.update(app.config)
TaskBase = celery.Task TaskBase = celery.Task

6
docs/patterns/deferredcallbacks.rst

@ -56,9 +56,9 @@ this the following function needs to be registered as
A Practical Example A Practical Example
------------------- -------------------
Now we can easily at any point in time register a function to be called at At any time during a request, we can register a function to be called at the
the end of this particular request. For example you can remember the end of the request. For example you can remember the current language of the
current language of the user in a cookie in the before-request function:: user in a cookie in the before-request function::
from flask import request from flask import request

101
docs/patterns/distribute.rst

@ -1,13 +1,12 @@
.. _distribute-deployment: .. _distribute-deployment:
Deploying with Distribute Deploying with Setuptools
========================= =========================
`distribute`_, formerly setuptools, is an extension library that is `Setuptools`_, is an extension library that is commonly used to
commonly used to (like the name says) distribute Python libraries and distribute Python libraries and extensions. It extends distutils, a basic
extensions. It extends distutils, a basic module installation system module installation system shipped with Python to also support various more
shipped with Python to also support various more complex constructs that complex constructs that make larger applications easier to distribute:
make larger applications easier to distribute:
- **support for dependencies**: a library or application can declare a - **support for dependencies**: a library or application can declare a
list of other libraries it depends on which will be installed list of other libraries it depends on which will be installed
@ -16,34 +15,32 @@ make larger applications easier to distribute:
Python installation. This makes it possible to query information Python installation. This makes it possible to query information
provided by one package from another package. The best known feature of provided by one package from another package. The best known feature of
this system is the entry point support which allows one package to this system is the entry point support which allows one package to
declare an "entry point" another package can hook into to extend the declare an "entry point" that another package can hook into to extend the
other package. other package.
- **installation manager**: :command:`easy_install`, which comes with distribute - **installation manager**: :command:`pip` can install other libraries for you.
can install other libraries for you. You can also use `pip`_ which
sooner or later will replace :command:`easy_install` which does more than just
installing packages for you.
Flask itself, and all the libraries you can find on the cheeseshop If you have Python 2 (>=2.7.9) or Python 3 (>=3.4) installed from python.org,
are distributed with either distribute, the older setuptools or distutils. you will already have pip and setuptools on your system. Otherwise, you
will need to install them yourself.
Flask itself, and all the libraries you can find on PyPI are distributed with
either setuptools or distutils.
In this case we assume your application is called In this case we assume your application is called
:file:`yourapplication.py` and you are not using a module, but a :ref:`package :file:`yourapplication.py` and you are not using a module, but a :ref:`package
<larger-applications>`. Distributing resources with standard modules is <larger-applications>`. If you have not yet converted your application into
not supported by `distribute`_ so we will not bother with it. If you have a package, head over to the :ref:`larger-applications` pattern to see
not yet converted your application into a package, head over to the how this can be done.
:ref:`larger-applications` pattern to see how this can be done.
A working deployment with distribute is the first step into more complex A working deployment with setuptools is the first step into more complex
and more automated deployment scenarios. If you want to fully automate and more automated deployment scenarios. If you want to fully automate
the process, also read the :ref:`fabric-deployment` chapter. the process, also read the :ref:`fabric-deployment` chapter.
Basic Setup Script Basic Setup Script
------------------ ------------------
Because you have Flask running, you either have setuptools or distribute Because you have Flask installed, you have setuptools available on your system.
available on your system anyways. If you do not, fear not, there is a Flask already depends upon setuptools.
script to install it for you: `distribute_setup.py`_. Just download and
run with your Python interpreter.
Standard disclaimer applies: :ref:`you better use a virtualenv Standard disclaimer applies: :ref:`you better use a virtualenv
<virtualenv>`. <virtualenv>`.
@ -52,10 +49,6 @@ Your setup code always goes into a file named :file:`setup.py` next to your
application. The name of the file is only convention, but because application. The name of the file is only convention, but because
everybody will look for a file with that name, you better not change it. everybody will look for a file with that name, you better not change it.
Yes, even if you are using `distribute`, you are importing from a package
called `setuptools`. `distribute` is fully backwards compatible with
`setuptools`, so it also uses the same import name.
A basic :file:`setup.py` file for a Flask application looks like this:: A basic :file:`setup.py` file for a Flask application looks like this::
from setuptools import setup from setuptools import setup
@ -71,8 +64,8 @@ A basic :file:`setup.py` file for a Flask application looks like this::
) )
Please keep in mind that you have to list subpackages explicitly. If you Please keep in mind that you have to list subpackages explicitly. If you
want distribute to lookup the packages for you automatically, you can use want setuptools to lookup the packages for you automatically, you can use
the `find_packages` function:: the ``find_packages`` function::
from setuptools import setup, find_packages from setuptools import setup, find_packages
@ -81,17 +74,36 @@ the `find_packages` function::
packages=find_packages() packages=find_packages()
) )
Most parameters to the `setup` function should be self explanatory, Most parameters to the ``setup`` function should be self explanatory,
`include_package_data` and `zip_safe` might not be. ``include_package_data`` and ``zip_safe`` might not be.
`include_package_data` tells distribute to look for a :file:`MANIFEST.in` file ``include_package_data`` tells setuptools to look for a :file:`MANIFEST.in` file
and install all the entries that match as package data. We will use this and install all the entries that match as package data. We will use this
to distribute the static files and templates along with the Python module to distribute the static files and templates along with the Python module
(see :ref:`distributing-resources`). The `zip_safe` flag can be used to (see :ref:`distributing-resources`). The ``zip_safe`` flag can be used to
force or prevent zip Archive creation. In general you probably don't want force or prevent zip Archive creation. In general you probably don't want
your packages to be installed as zip files because some tools do not your packages to be installed as zip files because some tools do not
support them and they make debugging a lot harder. support them and they make debugging a lot harder.
Tagging Builds
--------------
It is useful to distinguish between release and development builds. Add a
:file:`setup.cfg` file to configure these options.
[egg_info]
tag_build = .dev
tag_date = 1
[aliases]
release = egg_info -RDb ''
Running ``python setup.py sdist`` will create a development package
with ".dev" and the current date appended: ``flaskr-1.0.dev20160314.tar.gz``.
Running ``python setup.py release sdist`` will create a release package
with only the version: ``flaskr-1.0.tar.gz``.
.. _distributing-resources: .. _distributing-resources:
Distributing Resources Distributing Resources
@ -99,7 +111,7 @@ Distributing Resources
If you try to install the package you just created, you will notice that If you try to install the package you just created, you will notice that
folders like :file:`static` or :file:`templates` are not installed for you. The folders like :file:`static` or :file:`templates` are not installed for you. The
reason for this is that distribute does not know which files to add for reason for this is that setuptools does not know which files to add for
you. What you should do, is to create a :file:`MANIFEST.in` file next to your you. What you should do, is to create a :file:`MANIFEST.in` file next to your
:file:`setup.py` file. This file lists all the files that should be added to :file:`setup.py` file. This file lists all the files that should be added to
your tarball:: your tarball::
@ -109,13 +121,13 @@ your tarball::
Don't forget that even if you enlist them in your :file:`MANIFEST.in` file, they Don't forget that even if you enlist them in your :file:`MANIFEST.in` file, they
won't be installed for you unless you set the `include_package_data` won't be installed for you unless you set the `include_package_data`
parameter of the `setup` function to ``True``! parameter of the ``setup`` function to ``True``!
Declaring Dependencies Declaring Dependencies
---------------------- ----------------------
Dependencies are declared in the `install_requires` parameter as list. Dependencies are declared in the ``install_requires`` parameter as a list.
Each item in that list is the name of a package that should be pulled from Each item in that list is the name of a package that should be pulled from
PyPI on installation. By default it will always use the most recent PyPI on installation. By default it will always use the most recent
version, but you can also provide minimum and maximum version version, but you can also provide minimum and maximum version
@ -127,40 +139,39 @@ requirements. Here some examples::
'BrokenPackage>=0.7,<=1.0' 'BrokenPackage>=0.7,<=1.0'
] ]
I mentioned earlier that dependencies are pulled from PyPI. What if you As mentioned earlier, dependencies are pulled from PyPI. What if you
want to depend on a package that cannot be found on PyPI and won't be want to depend on a package that cannot be found on PyPI and won't be
because it is an internal package you don't want to share with anyone? because it is an internal package you don't want to share with anyone?
Just still do as if there was a PyPI entry for it and provide a list of Just do it as if there was a PyPI entry and provide a list of
alternative locations where distribute should look for tarballs:: alternative locations where setuptools should look for tarballs::
dependency_links=['http://example.com/yourfiles'] dependency_links=['http://example.com/yourfiles']
Make sure that page has a directory listing and the links on the page are Make sure that page has a directory listing and the links on the page are
pointing to the actual tarballs with their correct filenames as this is pointing to the actual tarballs with their correct filenames as this is
how distribute will find the files. If you have an internal company how setuptools will find the files. If you have an internal company
server that contains the packages, provide the URL to that server there. server that contains the packages, provide the URL to that server.
Installing / Developing Installing / Developing
----------------------- -----------------------
To install your application (ideally into a virtualenv) just run the To install your application (ideally into a virtualenv) just run the
:file:`setup.py` script with the `install` parameter. It will install your :file:`setup.py` script with the ``install`` parameter. It will install your
application into the virtualenv's site-packages folder and also download application into the virtualenv's site-packages folder and also download
and install all dependencies:: and install all dependencies::
$ python setup.py install $ python setup.py install
If you are developing on the package and also want the requirements to be If you are developing on the package and also want the requirements to be
installed, you can use the `develop` command instead:: installed, you can use the ``develop`` command instead::
$ python setup.py develop $ python setup.py develop
This has the advantage of just installing a link to the site-packages This has the advantage of just installing a link to the site-packages
folder instead of copying the data over. You can then continue to work on folder instead of copying the data over. You can then continue to work on
the code without having to run `install` again after each change. the code without having to run ``install`` again after each change.
.. _distribute: https://pypi.python.org/pypi/distribute
.. _pip: https://pypi.python.org/pypi/pip .. _pip: https://pypi.python.org/pypi/pip
.. _distribute_setup.py: http://python-distribute.org/distribute_setup.py .. _Setuptools: https://pypi.python.org/pypi/setuptools

38
docs/patterns/fabric.rst

@ -43,36 +43,25 @@ virtual environment::
env.hosts = ['server1.example.com', 'server2.example.com'] env.hosts = ['server1.example.com', 'server2.example.com']
def pack(): def pack():
# create a new source distribution as tarball # build the package
local('python setup.py sdist --formats=gztar', capture=False) local('python setup.py sdist --formats=gztar', capture=False)
def deploy(): def deploy():
# figure out the release name and version # figure out the package name and version
dist = local('python setup.py --fullname', capture=True).strip() dist = local('python setup.py --fullname', capture=True).strip()
# upload the source tarball to the temporary folder on the server filename = '%s.tar.gz' % dist
put('dist/%s.tar.gz' % dist, '/tmp/yourapplication.tar.gz')
# create a place where we can unzip the tarball, then enter # upload the package to the temporary folder on the server
# that directory and unzip it put('dist/%s' % filename, '/tmp/%s' % filename)
run('mkdir /tmp/yourapplication')
with cd('/tmp/yourapplication'):
run('tar xzf /tmp/yourapplication.tar.gz')
# now setup the package with our virtual environment's
# python interpreter
run('/var/www/yourapplication/env/bin/python setup.py install')
# now that all is set up, delete the folder again
run('rm -rf /tmp/yourapplication /tmp/yourapplication.tar.gz')
# and finally touch the .wsgi file so that mod_wsgi triggers
# a reload of the application
run('touch /var/www/yourapplication.wsgi')
The example above is well documented and should be straightforward. Here # install the package in the application's virtualenv with pip
a recap of the most common commands fabric provides: run('/var/www/yourapplication/env/bin/pip install /tmp/%s' % filename)
- `run` - executes a command on a remote server # remove the uploaded package
- `local` - executes a command on the local machine run('rm -r /tmp/%s' % filename)
- `put` - uploads a file to the remote server
- `cd` - changes the directory on the serverside. This has to be used # touch the .wsgi file to trigger a reload in mod_wsgi
in combination with the ``with`` statement. run('touch /var/www/yourapplication.wsgi')
Running Fabfiles Running Fabfiles
---------------- ----------------
@ -156,6 +145,7 @@ location where it's expected (eg: :file:`/var/www/yourapplication`).
Either way, in our case here we only expect one or two servers and we can Either way, in our case here we only expect one or two servers and we can
upload them ahead of time by hand. upload them ahead of time by hand.
First Deployment First Deployment
---------------- ----------------

2
docs/patterns/favicon.rst

@ -49,5 +49,5 @@ web server's documentation.
See also See also
-------- --------
* The `Favicon <http://en.wikipedia.org/wiki/Favicon>`_ article on * The `Favicon <https://en.wikipedia.org/wiki/Favicon>`_ article on
Wikipedia Wikipedia

22
docs/patterns/fileuploads.rst

@ -21,7 +21,7 @@ specific upload folder and displays a file to the user. Let's look at the
bootstrapping code for our application:: bootstrapping code for our application::
import os import os
from flask import Flask, request, redirect, url_for from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
UPLOAD_FOLDER = '/path/to/the/uploads' UPLOAD_FOLDER = '/path/to/the/uploads'
@ -40,14 +40,14 @@ your users to be able to upload everything there if the server is directly
sending out the data to the client. That way you can make sure that users sending out the data to the client. That way you can make sure that users
are not able to upload HTML files that would cause XSS problems (see are not able to upload HTML files that would cause XSS problems (see
:ref:`xss`). Also make sure to disallow ``.php`` files if the server :ref:`xss`). Also make sure to disallow ``.php`` files if the server
executes them, but who has PHP installed on his server, right? :) executes them, but who has PHP installed on their server, right? :)
Next the functions that check if an extension is valid and that uploads Next the functions that check if an extension is valid and that uploads
the file and redirects the user to the URL for the uploaded file:: the file and redirects the user to the URL for the uploaded file::
def allowed_file(filename): def allowed_file(filename):
return '.' in filename and \ return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST']) @app.route('/', methods=['GET', 'POST'])
def upload_file(): def upload_file():
@ -58,7 +58,7 @@ the file and redirects the user to the URL for the uploaded file::
return redirect(request.url) return redirect(request.url)
file = request.files['file'] file = request.files['file']
# if user does not select file, browser also # if user does not select file, browser also
# submit a empty part without filename # submit an empty part without filename
if file.filename == '': if file.filename == '':
flash('No selected file') flash('No selected file')
return redirect(request.url) return redirect(request.url)
@ -71,9 +71,9 @@ the file and redirects the user to the URL for the uploaded file::
<!doctype html> <!doctype html>
<title>Upload new File</title> <title>Upload new File</title>
<h1>Upload new File</h1> <h1>Upload new File</h1>
<form action="" method=post enctype=multipart/form-data> <form method=post enctype=multipart/form-data>
<p><input type=file name=file> <input type=file name=file>
<input type=submit value=Upload> <input type=submit value=Upload>
</form> </form>
''' '''
@ -104,9 +104,9 @@ before storing it directly on the filesystem.
>>> secure_filename('../../../../home/username/.bashrc') >>> secure_filename('../../../../home/username/.bashrc')
'home_username_.bashrc' 'home_username_.bashrc'
Now one last thing is missing: the serving of the uploaded files. In the Now one last thing is missing: the serving of the uploaded files. In the
:func:`upload_file()` we redirect the user to :func:`upload_file()` we redirect the user to
``url_for('uploaded_file', filename=filename)``, that is, ``/uploads/filename``. ``url_for('uploaded_file', filename=filename)``, that is, ``/uploads/filename``.
So we write the :func:`uploaded_file` function to return the file of that name. As So we write the :func:`uploaded_file` function to return the file of that name. As
of Flask 0.5 we can use a function that does that for us:: of Flask 0.5 we can use a function that does that for us::
@ -181,4 +181,4 @@ applications dealing with uploads, there is also a Flask extension called
blacklisting of extensions and more. blacklisting of extensions and more.
.. _jQuery: https://jquery.com/ .. _jQuery: https://jquery.com/
.. _Flask-Uploads: http://pythonhosted.org/Flask-Uploads/ .. _Flask-Uploads: https://pythonhosted.org/Flask-Uploads/

6
docs/patterns/flashing.rst

@ -9,7 +9,9 @@ application. Flask provides a really simple way to give feedback to a
user with the flashing system. The flashing system basically makes it user with the flashing system. The flashing system basically makes it
possible to record a message at the end of a request and access it next possible to record a message at the end of a request and access it next
request and only next request. This is usually combined with a layout request and only next request. This is usually combined with a layout
template that does this. template that does this. Note that browsers and sometimes web servers enforce
a limit on cookie sizes. This means that flashing messages that are too
large for session cookies causes message flashing to fail silently.
Simple Flashing Simple Flashing
--------------- ---------------
@ -76,7 +78,7 @@ And here is the :file:`login.html` template which also inherits from
{% if error %} {% if error %}
<p class=error><strong>Error:</strong> {{ error }} <p class=error><strong>Error:</strong> {{ error }}
{% endif %} {% endif %}
<form action="" method=post> <form method=post>
<dl> <dl>
<dt>Username: <dt>Username:
<dd><input type=text name=username value="{{ <dd><input type=text name=username value="{{

1
docs/patterns/index.rst

@ -41,3 +41,4 @@ Snippet Archives <http://flask.pocoo.org/snippets/>`_.
methodoverrides methodoverrides
requestchecksum requestchecksum
celery celery
subclassing

2
docs/patterns/jquery.rst

@ -164,5 +164,5 @@ explanation of the little bit of code above:
If you don't get the whole picture, download the `sourcecode If you don't get the whole picture, download the `sourcecode
for this example for this example
<https://github.com/mitsuhiko/flask/tree/master/examples/jqueryexample>`_ <https://github.com/pallets/flask/tree/master/examples/jqueryexample>`_
from GitHub. from GitHub.

15
docs/patterns/lazyloading.rst

@ -90,14 +90,19 @@ Then you can define your central place to combine the views like this::
You can further optimize this in terms of amount of keystrokes needed to You can further optimize this in terms of amount of keystrokes needed to
write this by having a function that calls into write this by having a function that calls into
:meth:`~flask.Flask.add_url_rule` by prefixing a string with the project :meth:`~flask.Flask.add_url_rule` by prefixing a string with the project
name and a dot, and by wrapping `view_func` in a `LazyView` as needed:: name and a dot, and by wrapping `view_func` in a `LazyView` as needed. ::
def url(url_rule, import_name, **options): def url(import_name, url_rules=[], **options):
view = LazyView('yourapplication.' + import_name) view = LazyView('yourapplication.' + import_name)
app.add_url_rule(url_rule, view_func=view, **options) for url_rule in url_rules:
app.add_url_rule(url_rule, view_func=view, **options)
url('/', 'views.index') # add a single route to the index view
url('/user/<username>', 'views.user') url('views.index', ['/'])
# add two routes to a single function endpoint
url_rules = ['/user/','/user/<username>']
url('views.user', url_rules)
One thing to keep in mind is that before and after request handlers have One thing to keep in mind is that before and after request handlers have
to be in a file that is imported upfront to work properly on the first to be in a file that is imported upfront to work properly on the first

52
docs/patterns/packages.rst

@ -8,15 +8,19 @@ module. That is quite simple. Imagine a small application looks like
this:: this::
/yourapplication /yourapplication
/yourapplication.py yourapplication.py
/static /static
/style.css style.css
/templates /templates
layout.html layout.html
index.html index.html
login.html login.html
... ...
If you find yourself stuck on something, feel free
to take a look at the source code for this example.
You'll find `the full src for this example here`_.
Simple Packages Simple Packages
--------------- ---------------
@ -29,9 +33,9 @@ You should then end up with something like that::
/yourapplication /yourapplication
/yourapplication /yourapplication
/__init__.py __init__.py
/static /static
/style.css style.css
/templates /templates
layout.html layout.html
index.html index.html
@ -41,11 +45,36 @@ You should then end up with something like that::
But how do you run your application now? The naive ``python But how do you run your application now? The naive ``python
yourapplication/__init__.py`` will not work. Let's just say that Python yourapplication/__init__.py`` will not work. Let's just say that Python
does not want modules in packages to be the startup file. But that is not does not want modules in packages to be the startup file. But that is not
a big problem, just add a new file called :file:`runserver.py` next to the inner a big problem, just add a new file called :file:`setup.py` next to the inner
:file:`yourapplication` folder with the following contents:: :file:`yourapplication` folder with the following contents::
from yourapplication import app from setuptools import setup
app.run(debug=True)
setup(
name='yourapplication',
packages=['yourapplication'],
include_package_data=True,
install_requires=[
'flask',
],
)
In order to run the application you need to export an environment variable
that tells Flask where to find the application instance::
export FLASK_APP=yourapplication
If you are outside of the project directory make sure to provide the exact
path to your application directory. Similarly you can turn on "debug
mode" with this environment variable::
export FLASK_DEBUG=true
In order to install and run the application you need to issue the following
commands::
pip install -e .
flask run
What did we gain from this? Now we can restructure the application a bit What did we gain from this? Now we can restructure the application a bit
into multiple modules. The only thing you have to remember is the into multiple modules. The only thing you have to remember is the
@ -77,12 +106,12 @@ And this is what :file:`views.py` would look like::
You should then end up with something like that:: You should then end up with something like that::
/yourapplication /yourapplication
/runserver.py setup.py
/yourapplication /yourapplication
/__init__.py __init__.py
/views.py views.py
/static /static
/style.css style.css
/templates /templates
layout.html layout.html
index.html index.html
@ -105,6 +134,7 @@ You should then end up with something like that::
.. _working-with-modules: .. _working-with-modules:
.. _the full src for this example here: https://github.com/pallets/flask/tree/master/examples/patterns/largerapp
Working with Blueprints Working with Blueprints
----------------------- -----------------------

10
docs/patterns/sqlalchemy.rst

@ -22,7 +22,7 @@ if you want to get started quickly.
You can download `Flask-SQLAlchemy`_ from `PyPI You can download `Flask-SQLAlchemy`_ from `PyPI
<https://pypi.python.org/pypi/Flask-SQLAlchemy>`_. <https://pypi.python.org/pypi/Flask-SQLAlchemy>`_.
.. _Flask-SQLAlchemy: http://pythonhosted.org/Flask-SQLAlchemy/ .. _Flask-SQLAlchemy: http://flask-sqlalchemy.pocoo.org/
Declarative Declarative
@ -108,9 +108,9 @@ Querying is simple as well:
>>> User.query.filter(User.name == 'admin').first() >>> User.query.filter(User.name == 'admin').first()
<User u'admin'> <User u'admin'>
.. _SQLAlchemy: http://www.sqlalchemy.org/ .. _SQLAlchemy: https://www.sqlalchemy.org/
.. _declarative: .. _declarative:
http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/ https://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/
Manual Object Relational Mapping Manual Object Relational Mapping
-------------------------------- --------------------------------
@ -135,7 +135,7 @@ Here is an example :file:`database.py` module for your application::
def init_db(): def init_db():
metadata.create_all(bind=engine) metadata.create_all(bind=engine)
As for the declarative approach you need to close the session after As in the declarative approach, you need to close the session after
each request or application context shutdown. Put this into your each request or application context shutdown. Put this into your
application module:: application module::
@ -215,4 +215,4 @@ You can also pass strings of SQL statements to the
(1, u'admin', u'admin@localhost') (1, u'admin', u'admin@localhost')
For more information about SQLAlchemy, head over to the For more information about SQLAlchemy, head over to the
`website <http://www.sqlalchemy.org/>`_. `website <https://www.sqlalchemy.org/>`_.

33
docs/patterns/sqlite3.rst

@ -3,8 +3,8 @@
Using SQLite 3 with Flask Using SQLite 3 with Flask
========================= =========================
In Flask you can easily implement the opening of database connections on In Flask you can easily implement the opening of database connections on
demand and closing them when the context dies (usually at the end of the demand and closing them when the context dies (usually at the end of the
request). request).
Here is a simple example of how you can use SQLite 3 with Flask:: Here is a simple example of how you can use SQLite 3 with Flask::
@ -71,7 +71,8 @@ Now in each request handling function you can access `g.db` to get the
current open database connection. To simplify working with SQLite, a current open database connection. To simplify working with SQLite, a
row factory function is useful. It is executed for every result returned row factory function is useful. It is executed for every result returned
from the database to convert the result. For instance, in order to get from the database to convert the result. For instance, in order to get
dictionaries instead of tuples, this could be inserted into ``get_db``:: dictionaries instead of tuples, this could be inserted into the ``get_db``
function we created above::
def make_dicts(cursor, row): def make_dicts(cursor, row):
return dict((cursor.description[idx][0], value) return dict((cursor.description[idx][0], value)
@ -79,21 +80,37 @@ dictionaries instead of tuples, this could be inserted into ``get_db``::
db.row_factory = make_dicts db.row_factory = make_dicts
Or even simpler:: This will make the sqlite3 module return dicts for this database connection, which are much nicer to deal with. Even more simply, we could place this in ``get_db`` instead::
db.row_factory = sqlite3.Row db.row_factory = sqlite3.Row
This would use Row objects rather than dicts to return the results of queries. These are ``namedtuple`` s, so we can access them either by index or by key. For example, assuming we have a ``sqlite3.Row`` called ``r`` for the rows ``id``, ``FirstName``, ``LastName``, and ``MiddleInitial``::
>>> # You can get values based on the row's name
>>> r['FirstName']
John
>>> # Or, you can get them based on index
>>> r[1]
John
# Row objects are also iterable:
>>> for value in r:
... print(value)
1
John
Doe
M
Additionally, it is a good idea to provide a query function that combines Additionally, it is a good idea to provide a query function that combines
getting the cursor, executing and fetching the results:: getting the cursor, executing and fetching the results::
def query_db(query, args=(), one=False): def query_db(query, args=(), one=False):
cur = get_db().execute(query, args) cur = get_db().execute(query, args)
rv = cur.fetchall() rv = cur.fetchall()
cur.close() cur.close()
return (rv[0] if rv else None) if one else rv return (rv[0] if rv else None) if one else rv
This handy little function, in combination with a row factory, makes This handy little function, in combination with a row factory, makes
working with the database much more pleasant than it is by just using the working with the database much more pleasant than it is by just using the
raw cursor and connection objects. raw cursor and connection objects.
Here is how you can use it:: Here is how you can use it::
@ -114,7 +131,7 @@ To pass variable parts to the SQL statement, use a question mark in the
statement and pass in the arguments as a list. Never directly add them to statement and pass in the arguments as a list. Never directly add them to
the SQL statement with string formatting because this makes it possible the SQL statement with string formatting because this makes it possible
to attack the application using `SQL Injections to attack the application using `SQL Injections
<http://en.wikipedia.org/wiki/SQL_injection>`_. <https://en.wikipedia.org/wiki/SQL_injection>`_.
Initial Schemas Initial Schemas
--------------- ---------------

17
docs/patterns/subclassing.rst

@ -0,0 +1,17 @@
Subclassing Flask
=================
The :class:`~flask.Flask` class is designed for subclassing.
For example, you may want to override how request parameters are handled to preserve their order::
from flask import Flask, Request
from werkzeug.datastructures import ImmutableOrderedMultiDict
class MyRequest(Request):
"""Request subclass to override request parameter storage"""
parameter_storage_class = ImmutableOrderedMultiDict
class MyFlask(Flask):
"""Flask subclass using the custom request class"""
request_class = MyRequest
This is the recommended approach for overriding or augmenting Flask's internal functionality.

27
docs/patterns/viewdecorators.rst

@ -16,15 +16,13 @@ Login Required Decorator
------------------------ ------------------------
So let's implement such a decorator. A decorator is a function that So let's implement such a decorator. A decorator is a function that
returns a function. Pretty simple actually. The only thing you have to wraps and replaces another function. Since the original function is
keep in mind when implementing something like this is to update the replaced, you need to remember to copy the original function's information
`__name__`, `__module__` and some other attributes of a function. This is to the new function. Use :func:`functools.wraps` to handle this for you.
often forgotten, but you don't have to do that by hand, there is a
function for that that is used like a decorator (:func:`functools.wraps`).
This example assumes that the login page is called ``'login'`` and that This example assumes that the login page is called ``'login'`` and that
the current user is stored as `g.user` and ``None`` if there is no-one the current user is stored in ``g.user`` and is ``None`` if there is no-one
logged in:: logged in. ::
from functools import wraps from functools import wraps
from flask import g, request, redirect, url_for from flask import g, request, redirect, url_for
@ -37,15 +35,24 @@ logged in::
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated_function return decorated_function
So how would you use that decorator now? Apply it as innermost decorator To use the decorator, apply it as innermost decorator to a view function.
to a view function. When applying further decorators, always remember When applying further decorators, always remember
that the :meth:`~flask.Flask.route` decorator is the outermost:: that the :meth:`~flask.Flask.route` decorator is the outermost. ::
@app.route('/secret_page') @app.route('/secret_page')
@login_required @login_required
def secret_page(): def secret_page():
pass pass
.. note::
The ``next`` value will exist in ``request.args`` after a ``GET`` request for
the login page. You'll have to pass it along when sending the ``POST`` request
from the login form. You can do this with a hidden input tag, then retrieve it
from ``request.form`` when logging the user in. ::
<input type="hidden" value="{{ request.args.get('next', '') }}"/>
Caching Decorator Caching Decorator
----------------- -----------------

12
docs/patterns/wtforms.rst

@ -19,7 +19,7 @@ forms.
fun. You can get it from `PyPI fun. You can get it from `PyPI
<https://pypi.python.org/pypi/Flask-WTF>`_. <https://pypi.python.org/pypi/Flask-WTF>`_.
.. _Flask-WTF: http://pythonhosted.org/Flask-WTF/ .. _Flask-WTF: https://flask-wtf.readthedocs.io/en/stable/
The Forms The Forms
--------- ---------
@ -32,11 +32,11 @@ This is an example form for a typical registration page::
username = StringField('Username', [validators.Length(min=4, max=25)]) username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)]) email = StringField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('New Password', [ password = PasswordField('New Password', [
validators.Required(), validators.DataRequired(),
validators.EqualTo('confirm', message='Passwords must match') validators.EqualTo('confirm', message='Passwords must match')
]) ])
confirm = PasswordField('Repeat Password') confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.Required()]) accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
In the View In the View
----------- -----------
@ -108,7 +108,7 @@ takes advantage of the :file:`_formhelpers.html` template:
.. sourcecode:: html+jinja .. sourcecode:: html+jinja
{% from "_formhelpers.html" import render_field %} {% from "_formhelpers.html" import render_field %}
<form method=post action="/register"> <form method=post>
<dl> <dl>
{{ render_field(form.username) }} {{ render_field(form.username) }}
{{ render_field(form.email) }} {{ render_field(form.email) }}
@ -122,5 +122,5 @@ takes advantage of the :file:`_formhelpers.html` template:
For more information about WTForms, head over to the `WTForms For more information about WTForms, head over to the `WTForms
website`_. website`_.
.. _WTForms: http://wtforms.readthedocs.org/ .. _WTForms: https://wtforms.readthedocs.io/
.. _WTForms website: http://wtforms.readthedocs.org/ .. _WTForms website: https://wtforms.readthedocs.io/

39
docs/python3.rst

@ -3,32 +3,21 @@
Python 3 Support Python 3 Support
================ ================
Flask and all of its dependencies support Python 3 so you can in theory Flask, its dependencies, and most Flask extensions support Python 3.
start working on it already. There are however a few things you should be You should start using Python 3 for your next project,
aware of before you start using Python 3 for your next project. but there are a few things to be aware of.
If you want to use Flask with Python 3 you will need to use Python 3.3 or You need to use Python 3.3 or higher. 3.2 and older are *not* supported.
higher. 3.2 and older are *not* supported.
In addition to that you need to use the latest and greatest versions of You should use the latest versions of all Flask-related packages.
`itsdangerous`, `Jinja2` and `Werkzeug`. Flask 0.10 and Werkzeug 0.9 were Flask 0.10 and Werkzeug 0.9 were the first versions to introduce Python 3 support.
the first versions to introduce Python 3 support.
Some of the decisions made in regards to unicode and byte utilization on Python 3 changed how unicode and bytes are handled, which complicates how low
Python 3 make it hard to write low level code. This mainly affects WSGI level code handles HTTP data. This mainly affects WSGI middleware interacting
middlewares and interacting with the WSGI provided information. Werkzeug with the WSGI ``environ`` data. Werkzeug wraps that information in high-level
wraps all that information in high-level helpers but some of those were helpers, so encoding issues should not affect you.
specifically added for the Python 3 support and are quite new.
Unless you require absolute compatibility, you should be fine with Python 3 The majority of the upgrade work is in the lower-level libraries like
nowadays. Most libraries and Flask extensions have been ported by now and Flask and Werkzeug, not the high-level application code.
using Flask with Python 3 is generally a smooth ride. However, keep in mind For example, all of the examples in the Flask repository work on both Python 2 and 3
that most libraries (including Werkzeug and Flask) might not quite as stable and did not require a single line of code changed.
on Python 3 yet. You might therefore sometimes run into bugs that are
usually encoding-related.
The majority of the upgrade pain is in the lower-level libraries like
Flask and Werkzeug and not in the actual high-level application code. For
instance all of the Flask examples that are in the Flask repository work
out of the box on both 2.x and 3.x and did not require a single line of
code changed.

181
docs/quickstart.rst

@ -26,7 +26,7 @@ So what did that code do?
class will be our WSGI application. class will be our WSGI application.
2. Next we create an instance of this class. The first argument is the name of 2. Next we create an instance of this class. The first argument is the name of
the application's module or package. If you are using a single module (as the application's module or package. If you are using a single module (as
in this example), you should use `__name__` because depending on if it's in this example), you should use ``__name__`` because depending on if it's
started as application or imported as module the name will be different started as application or imported as module the name will be different
(``'__main__'`` versus the actual import name). This is needed so that (``'__main__'`` versus the actual import name). This is needed so that
Flask knows where to look for templates, static files, and so on. For more Flask knows where to look for templates, static files, and so on. For more
@ -37,19 +37,25 @@ So what did that code do?
particular function, and returns the message we want to display in the particular function, and returns the message we want to display in the
user's browser. user's browser.
Just save it as :file:`hello.py` (or something similar) and run it with your Python Just save it as :file:`hello.py` or something similar. Make sure to not call
interpreter. Make sure to not call your application :file:`flask.py` because this your application :file:`flask.py` because this would conflict with Flask
would conflict with Flask itself. itself.
To run the application you can either use the :command:`flask` command or To run the application you can either use the :command:`flask` command or
python's :option:`-m` switch with Flask:: python's ``-m`` switch with Flask. Before you can do that you need
to tell your terminal the application to work with by exporting the
``FLASK_APP`` environment variable::
$ flask -a hello run $ export FLASK_APP=hello.py
$ flask run
* Running on http://127.0.0.1:5000/ * Running on http://127.0.0.1:5000/
or alternatively:: If you are on Windows you need to use ``set`` instead of ``export``.
$ python -m flask -a hello run Alternatively you can use :command:`python -m flask`::
$ export FLASK_APP=hello.py
$ python -m flask run
* Running on http://127.0.0.1:5000/ * Running on http://127.0.0.1:5000/
This launches a very simple builtin server, which is good enough for testing This launches a very simple builtin server, which is good enough for testing
@ -72,7 +78,7 @@ should see your hello world greeting.
you can make the server publicly available simply by adding you can make the server publicly available simply by adding
``--host=0.0.0.0`` to the command line:: ``--host=0.0.0.0`` to the command line::
flask -a hello run --host=0.0.0.0 flask run --host=0.0.0.0
This tells your operating system to listen on all public IPs. This tells your operating system to listen on all public IPs.
@ -80,35 +86,26 @@ should see your hello world greeting.
What to do if the Server does not Start What to do if the Server does not Start
--------------------------------------- ---------------------------------------
In case the ``python -m flask`` fails or :command:`flask` does not exist, In case the :command:`python -m flask` fails or :command:`flask` does not exist,
there are multiple reasons this might be the case. First of all you need there are multiple reasons this might be the case. First of all you need
to look at the error message. to look at the error message.
Old Version of Flask Old Version of Flask
```````````````````` ````````````````````
Versions of Flask older than 1.0 use to have different ways to start the Versions of Flask older than 0.11 use to have different ways to start the
application. In short, the :command:`flask` command did not exist, and application. In short, the :command:`flask` command did not exist, and
neither did ``python -m flask``. In that case you have two options: neither did :command:`python -m flask`. In that case you have two options:
either upgrade to newer Flask versions or have a look at the :ref:`server` either upgrade to newer Flask versions or have a look at the :ref:`server`
docs to see the alternative method for running a server. docs to see the alternative method for running a server.
Python older 2.7
````````````````
In case you have a version of Python older than 2.7 ``python -m flask``
does not work. You can either use :command:`flask` or ``python -m
flask.cli`` as an alternative. This is because Python before 2.7 does no
permit packages to act as executable modules. For more information see
:ref:`cli`.
Invalid Import Name Invalid Import Name
``````````````````` ```````````````````
The :option:`-a` argument to :command:`flask` is the name of the module to import. In The ``FLASK_APP`` environment variable is the name of the module to import at
case that module is incorrectly named you will get an import error upon :command:`flask run`. In case that module is incorrectly named you will get an
start (or if debug is enabled when you navigate to the application). It import error upon start (or if debug is enabled when you navigate to the
will tell you what it tried to import and why it failed. application). It will tell you what it tried to import and why it failed.
The most common reason is a typo or because you did not actually create an The most common reason is a typo or because you did not actually create an
``app`` object. ``app`` object.
@ -126,10 +123,13 @@ That is not very nice and Flask can do better. If you enable debug
support the server will reload itself on code changes, and it will also support the server will reload itself on code changes, and it will also
provide you with a helpful debugger if things go wrong. provide you with a helpful debugger if things go wrong.
There are different ways to enable the debug mode. The most obvious one To enable debug mode you can export the ``FLASK_DEBUG`` environment variable
is the :option:`--debug` parameter to the :command:`flask` command:: before running the server::
flask --debug -a hello run $ export FLASK_DEBUG=1
$ flask run
(On Windows you need to use ``set`` instead of ``export``).
This does the following things: This does the following things:
@ -202,8 +202,10 @@ The following converters exist:
=========== =============================================== =========== ===============================================
`string` accepts any text without a slash (the default) `string` accepts any text without a slash (the default)
`int` accepts integers `int` accepts integers
`float` like `int` but for floating point values `float` like ``int`` but for floating point values
`path` like the default but also accepts slashes `path` like the default but also accepts slashes
`any` matches one of the items provided
`uuid` accepts UUID strings
=========== =============================================== =========== ===============================================
.. admonition:: Unique URLs / Redirection Behavior .. admonition:: Unique URLs / Redirection Behavior
@ -224,7 +226,7 @@ The following converters exist:
Though they look rather similar, they differ in their use of the trailing Though they look rather similar, they differ in their use of the trailing
slash in the URL *definition*. In the first case, the canonical URL for the slash in the URL *definition*. In the first case, the canonical URL for the
`projects` endpoint has a trailing slash. In that sense, it is similar to ``projects`` endpoint has a trailing slash. In that sense, it is similar to
a folder on a filesystem. Accessing it without a trailing slash will cause a folder on a filesystem. Accessing it without a trailing slash will cause
Flask to redirect to the canonical URL with the trailing slash. Flask to redirect to the canonical URL with the trailing slash.
@ -248,29 +250,29 @@ build a URL to a specific function you can use the :func:`~flask.url_for`
function. It accepts the name of the function as first argument and a number function. It accepts the name of the function as first argument and a number
of keyword arguments, each corresponding to the variable part of the URL rule. of keyword arguments, each corresponding to the variable part of the URL rule.
Unknown variable parts are appended to the URL as query parameters. Here are Unknown variable parts are appended to the URL as query parameters. Here are
some examples: some examples::
>>> from flask import Flask, url_for >>> from flask import Flask, url_for
>>> app = Flask(__name__) >>> app = Flask(__name__)
>>> @app.route('/') >>> @app.route('/')
... def index(): pass ... def index(): pass
... ...
>>> @app.route('/login') >>> @app.route('/login')
... def login(): pass ... def login(): pass
... ...
>>> @app.route('/user/<username>') >>> @app.route('/user/<username>')
... def profile(username): pass ... def profile(username): pass
... ...
>>> with app.test_request_context(): >>> with app.test_request_context():
... print url_for('index') ... print(url_for('index'))
... print url_for('login') ... print(url_for('login'))
... print url_for('login', next='/') ... print(url_for('login', next='/'))
... print url_for('profile', username='John Doe') ... print(url_for('profile', username='John Doe'))
... ...
/ /
/login /login
/login?next=/ /login?next=/
/user/John%20Doe /user/John%20Doe
(This also uses the :meth:`~flask.Flask.test_request_context` method, explained (This also uses the :meth:`~flask.Flask.test_request_context` method, explained
below. It tells Flask to behave as though it is handling a request, even below. It tells Flask to behave as though it is handling a request, even
@ -286,8 +288,8 @@ There are three good reasons for this:
remember to change URLs all over the place. remember to change URLs all over the place.
2. URL building will handle escaping of special characters and Unicode 2. URL building will handle escaping of special characters and Unicode
data transparently for you, so you don't have to deal with them. data transparently for you, so you don't have to deal with them.
3. If your application is placed outside the URL root (say, in 3. If your application is placed outside the URL root - say, in
``/myapplication`` instead of ``/``), :func:`~flask.url_for` will handle ``/myapplication`` instead of ``/`` - :func:`~flask.url_for` will handle
that properly for you. that properly for you.
@ -296,7 +298,7 @@ HTTP Methods
HTTP (the protocol web applications are speaking) knows different methods for HTTP (the protocol web applications are speaking) knows different methods for
accessing URLs. By default, a route only answers to ``GET`` requests, but that accessing URLs. By default, a route only answers to ``GET`` requests, but that
can be changed by providing the `methods` argument to the can be changed by providing the ``methods`` argument to the
:meth:`~flask.Flask.route` decorator. Here are some examples:: :meth:`~flask.Flask.route` decorator. Here are some examples::
from flask import request from flask import request
@ -304,9 +306,9 @@ can be changed by providing the `methods` argument to the
@app.route('/login', methods=['GET', 'POST']) @app.route('/login', methods=['GET', 'POST'])
def login(): def login():
if request.method == 'POST': if request.method == 'POST':
do_the_login() return do_the_login()
else: else:
show_the_login_form() return show_the_login_form()
If ``GET`` is present, ``HEAD`` will be added automatically for you. You If ``GET`` is present, ``HEAD`` will be added automatically for you. You
don't have to deal with that. It will also make sure that ``HEAD`` requests don't have to deal with that. It will also make sure that ``HEAD`` requests
@ -319,7 +321,7 @@ You have no idea what an HTTP method is? Worry not, here is a quick
introduction to HTTP methods and why they matter: introduction to HTTP methods and why they matter:
The HTTP method (also often called "the verb") tells the server what the The HTTP method (also often called "the verb") tells the server what the
clients wants to *do* with the requested page. The following methods are client wants to *do* with the requested page. The following methods are
very common: very common:
``GET`` ``GET``
@ -365,7 +367,7 @@ HTTP has become quite popular lately and browsers are no longer the only
clients that are using HTTP. For instance, many revision control systems clients that are using HTTP. For instance, many revision control systems
use it. use it.
.. _HTTP RFC: http://www.ietf.org/rfc/rfc2068.txt .. _HTTP RFC: https://www.ietf.org/rfc/rfc2068.txt
Static Files Static Files
------------ ------------
@ -444,22 +446,22 @@ know how that works, head over to the :ref:`template-inheritance` pattern
documentation. Basically template inheritance makes it possible to keep documentation. Basically template inheritance makes it possible to keep
certain elements on each page (like header, navigation and footer). certain elements on each page (like header, navigation and footer).
Automatic escaping is enabled, so if `name` contains HTML it will be escaped Automatic escaping is enabled, so if ``name`` contains HTML it will be escaped
automatically. If you can trust a variable and you know that it will be automatically. If you can trust a variable and you know that it will be
safe HTML (for example because it came from a module that converts wiki safe HTML (for example because it came from a module that converts wiki
markup to HTML) you can mark it as safe by using the markup to HTML) you can mark it as safe by using the
:class:`~jinja2.Markup` class or by using the ``|safe`` filter in the :class:`~jinja2.Markup` class or by using the ``|safe`` filter in the
template. Head over to the Jinja 2 documentation for more examples. template. Head over to the Jinja 2 documentation for more examples.
Here is a basic introduction to how the :class:`~jinja2.Markup` class works: Here is a basic introduction to how the :class:`~jinja2.Markup` class works::
>>> from flask import Markup >>> from flask import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>' >>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup(u'<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>') Markup(u'<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>')
>>> Markup.escape('<blink>hacker</blink>') >>> Markup.escape('<blink>hacker</blink>')
Markup(u'&lt;blink&gt;hacker&lt;/blink&gt;') Markup(u'&lt;blink&gt;hacker&lt;/blink&gt;')
>>> Markup('<em>Marked up</em> &raquo; HTML').striptags() >>> Markup('<em>Marked up</em> &raquo; HTML').striptags()
u'Marked up \xbb HTML' u'Marked up \xbb HTML'
.. versionchanged:: 0.5 .. versionchanged:: 0.5
@ -536,16 +538,16 @@ The Request Object
`````````````````` ``````````````````
The request object is documented in the API section and we will not cover The request object is documented in the API section and we will not cover
it here in detail (see :class:`~flask.request`). Here is a broad overview of it here in detail (see :class:`~flask.Request`). Here is a broad overview of
some of the most common operations. First of all you have to import it from some of the most common operations. First of all you have to import it from
the `flask` module:: the ``flask`` module::
from flask import request from flask import request
The current request method is available by using the The current request method is available by using the
:attr:`~flask.request.method` attribute. To access form data (data :attr:`~flask.Request.method` attribute. To access form data (data
transmitted in a ``POST`` or ``PUT`` request) you can use the transmitted in a ``POST`` or ``PUT`` request) you can use the
:attr:`~flask.request.form` attribute. Here is a full example of the two :attr:`~flask.Request.form` attribute. Here is a full example of the two
attributes mentioned above:: attributes mentioned above::
@app.route('/login', methods=['POST', 'GET']) @app.route('/login', methods=['POST', 'GET'])
@ -561,14 +563,14 @@ attributes mentioned above::
# was GET or the credentials were invalid # was GET or the credentials were invalid
return render_template('login.html', error=error) return render_template('login.html', error=error)
What happens if the key does not exist in the `form` attribute? In that What happens if the key does not exist in the ``form`` attribute? In that
case a special :exc:`KeyError` is raised. You can catch it like a case a special :exc:`KeyError` is raised. You can catch it like a
standard :exc:`KeyError` but if you don't do that, a HTTP 400 Bad Request standard :exc:`KeyError` but if you don't do that, a HTTP 400 Bad Request
error page is shown instead. So for many situations you don't have to error page is shown instead. So for many situations you don't have to
deal with that problem. deal with that problem.
To access parameters submitted in the URL (``?key=value``) you can use the To access parameters submitted in the URL (``?key=value``) you can use the
:attr:`~flask.request.args` attribute:: :attr:`~flask.Request.args` attribute::
searchword = request.args.get('key', '') searchword = request.args.get('key', '')
@ -577,7 +579,7 @@ We recommend accessing URL parameters with `get` or by catching the
bad request page in that case is not user friendly. bad request page in that case is not user friendly.
For a full list of methods and attributes of the request object, head over For a full list of methods and attributes of the request object, head over
to the :class:`~flask.request` documentation. to the :class:`~flask.Request` documentation.
File Uploads File Uploads
@ -723,17 +725,15 @@ converting return values into response objects is as follows:
3. If a tuple is returned the items in the tuple can provide extra 3. If a tuple is returned the items in the tuple can provide extra
information. Such tuples have to be in the form ``(response, status, information. Such tuples have to be in the form ``(response, status,
headers)`` or ``(response, headers)`` where at least one item has headers)`` or ``(response, headers)`` where at least one item has
to be in the tuple. The `status` value will override the status code to be in the tuple. The ``status`` value will override the status code
and `headers` can be a list or dictionary of additional header values. and ``headers`` can be a list or dictionary of additional header values.
4. If none of that works, Flask will assume the return value is a 4. If none of that works, Flask will assume the return value is a
valid WSGI application and convert that into a response object. valid WSGI application and convert that into a response object.
If you want to get hold of the resulting response object inside the view If you want to get hold of the resulting response object inside the view
you can use the :func:`~flask.make_response` function. you can use the :func:`~flask.make_response` function.
Imagine you have a view like this: Imagine you have a view like this::
.. sourcecode:: python
@app.errorhandler(404) @app.errorhandler(404)
def not_found(error): def not_found(error):
@ -741,9 +741,7 @@ Imagine you have a view like this:
You just need to wrap the return expression with You just need to wrap the return expression with
:func:`~flask.make_response` and get the response object to modify it, then :func:`~flask.make_response` and get the response object to modify it, then
return it: return it::
.. sourcecode:: python
@app.errorhandler(404) @app.errorhandler(404)
def not_found(error): def not_found(error):
@ -782,7 +780,7 @@ sessions work::
session['username'] = request.form['username'] session['username'] = request.form['username']
return redirect(url_for('index')) return redirect(url_for('index'))
return ''' return '''
<form action="" method="post"> <form method="post">
<p><input type=text name=username> <p><input type=text name=username>
<p><input type=submit value=Login> <p><input type=submit value=Login>
</form> </form>
@ -805,13 +803,13 @@ not using the template engine (as in this example).
The problem with random is that it's hard to judge what is truly random. And The problem with random is that it's hard to judge what is truly random. And
a secret key should be as random as possible. Your operating system a secret key should be as random as possible. Your operating system
has ways to generate pretty random stuff based on a cryptographic has ways to generate pretty random stuff based on a cryptographic
random generator which can be used to get such a key: random generator which can be used to get such a key::
>>> import os >>> import os
>>> os.urandom(24) >>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8' '\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
Just take that thing and copy/paste it into your code and you're done. Just take that thing and copy/paste it into your code and you're done.
A note on cookie-based sessions: Flask will take the values you put into the A note on cookie-based sessions: Flask will take the values you put into the
session object and serialize them into a cookie. If you are finding some session object and serialize them into a cookie. If you are finding some
@ -819,6 +817,9 @@ values do not persist across requests, cookies are indeed enabled, and you are
not getting a clear error message, check the size of the cookie in your page not getting a clear error message, check the size of the cookie in your page
responses compared to the size supported by web browsers. responses compared to the size supported by web browsers.
Besides the default client-side based sessions, if you want to handle
sessions on the server-side instead, there are several
Flask extensions that support this.
Message Flashing Message Flashing
---------------- ----------------

2
docs/reqcontext.rst

@ -69,7 +69,7 @@ find a piece of code that looks very much like this::
with self.request_context(environ): with self.request_context(environ):
try: try:
response = self.full_dispatch_request() response = self.full_dispatch_request()
except Exception, e: except Exception as e:
response = self.make_response(self.handle_exception(e)) response = self.make_response(self.handle_exception(e))
return response(environ, start_response) return response(environ, start_response)

89
docs/security.rst

@ -15,7 +15,7 @@ it JavaScript) into the context of a website. To remedy this, developers
have to properly escape text so that it cannot include arbitrary HTML have to properly escape text so that it cannot include arbitrary HTML
tags. For more information on that have a look at the Wikipedia article tags. For more information on that have a look at the Wikipedia article
on `Cross-Site Scripting on `Cross-Site Scripting
<http://en.wikipedia.org/wiki/Cross-site_scripting>`_. <https://en.wikipedia.org/wiki/Cross-site_scripting>`_.
Flask configures Jinja2 to automatically escape all values unless Flask configures Jinja2 to automatically escape all values unless
explicitly told otherwise. This should rule out all XSS problems caused explicitly told otherwise. This should rule out all XSS problems caused
@ -73,7 +73,7 @@ them knowing.
Say you have a specific URL that, when you sent ``POST`` requests to will Say you have a specific URL that, when you sent ``POST`` requests to will
delete a user's profile (say ``http://example.com/user/delete``). If an delete a user's profile (say ``http://example.com/user/delete``). If an
attacker now creates a page that sends a post request to that page with attacker now creates a page that sends a post request to that page with
some JavaScript they just has to trick some users to load that page and some JavaScript they just have to trick some users to load that page and
their profiles will end up being deleted. their profiles will end up being deleted.
Imagine you were to run Facebook with millions of concurrent users and Imagine you were to run Facebook with millions of concurrent users and
@ -95,81 +95,12 @@ the form validation framework, which does not exist in Flask.
JSON Security JSON Security
------------- -------------
.. admonition:: ECMAScript 5 Changes In Flask 0.10 and lower, :func:`~flask.jsonify` did not serialize top-level
arrays to JSON. This was because of a security vulnerability in ECMAScript 4.
Starting with ECMAScript 5 the behavior of literals changed. Now they ECMAScript 5 closed this vulnerability, so only extremely old browsers are
are not constructed with the constructor of ``Array`` and others, but still vulnerable. All of these browsers have `other more serious
with the builtin constructor of ``Array`` which closes this particular vulnerabilities
attack vector. <https://github.com/pallets/flask/issues/248#issuecomment-59934857>`_, so
this behavior was changed and :func:`~flask.jsonify` now supports serializing
JSON itself is a high-level serialization format, so there is barely arrays.
anything that could cause security problems, right? You can't declare
recursive structures that could cause problems and the only thing that
could possibly break are very large responses that can cause some kind of
denial of service at the receiver's side.
However there is a catch. Due to how browsers work the CSRF issue comes
up with JSON unfortunately. Fortunately there is also a weird part of the
JavaScript specification that can be used to solve that problem easily and
Flask is kinda doing that for you by preventing you from doing dangerous
stuff. Unfortunately that protection is only there for
:func:`~flask.jsonify` so you are still at risk when using other ways to
generate JSON.
So what is the issue and how to avoid it? The problem are arrays at
top-level in JSON. Imagine you send the following data out in a JSON
request. Say that's exporting the names and email addresses of all your
friends for a part of the user interface that is written in JavaScript.
Not very uncommon:
.. sourcecode:: javascript
[
{"username": "admin",
"email": "admin@localhost"}
]
And it is doing that of course only as long as you are logged in and only
for you. And it is doing that for all ``GET`` requests to a certain URL,
say the URL for that request is
``http://example.com/api/get_friends.json``.
So now what happens if a clever hacker is embedding this to his website
and social engineers a victim to visiting his site:
.. sourcecode:: html
<script type=text/javascript>
var captured = [];
var oldArray = Array;
function Array() {
var obj = this, id = 0, capture = function(value) {
obj.__defineSetter__(id++, capture);
if (value)
captured.push(value);
};
capture();
}
</script>
<script type=text/javascript
src=http://example.com/api/get_friends.json></script>
<script type=text/javascript>
Array = oldArray;
// now we have all the data in the captured array.
</script>
If you know a bit of JavaScript internals you might know that it's
possible to patch constructors and register callbacks for setters. An
attacker can use this (like above) to get all the data you exported in
your JSON file. The browser will totally ignore the :mimetype:`application/json`
mimetype if :mimetype:`text/javascript` is defined as content type in the script
tag and evaluate that as JavaScript. Because top-level array elements are
allowed (albeit useless) and we hooked in our own constructor, after that
page loaded the data from the JSON response is in the `captured` array.
Because it is a syntax error in JavaScript to have an object literal
(``{...}``) toplevel an attacker could not just do a request to an
external URL with the script tag to load up the data. So what Flask does
is to only allow objects as toplevel elements when using
:func:`~flask.jsonify`. Make sure to do the same when using an ordinary
JSON generate function.

18
docs/server.rst

@ -5,7 +5,7 @@ Development Server
.. currentmodule:: flask .. currentmodule:: flask
Starting with Flask 1.0 there are multiple built-in ways to run a Starting with Flask 0.11 there are multiple built-in ways to run a
development server. The best one is the :command:`flask` command line utility development server. The best one is the :command:`flask` command line utility
but you can also continue using the :meth:`Flask.run` method. but you can also continue using the :meth:`Flask.run` method.
@ -16,7 +16,9 @@ The :command:`flask` command line script (:ref:`cli`) is strongly recommended fo
development because it provides a superior reload experience due to how it development because it provides a superior reload experience due to how it
loads the application. The basic usage is like this:: loads the application. The basic usage is like this::
$ flask -a my_application --debug run $ export FLASK_APP=my_application
$ export FLASK_DEBUG=1
$ flask run
This will enable the debugger, the reloader and then start the server on This will enable the debugger, the reloader and then start the server on
*http://localhost:5000/*. *http://localhost:5000/*.
@ -25,7 +27,7 @@ The individual features of the server can be controlled by passing more
arguments to the ``run`` option. For instance the reloader can be arguments to the ``run`` option. For instance the reloader can be
disabled:: disabled::
$ flask -a my_application --debug run --no-reload $ flask run --no-reload
In Code In Code
------- -------
@ -40,11 +42,11 @@ Example::
app.run() app.run()
This works well for the common case but it does not work well for This works well for the common case but it does not work well for
development which is why from Flask 1.0 onwards the :command:`flask` method is development which is why from Flask 0.11 onwards the :command:`flask`
recommended. The reason for this is that due to how the reload mechanism method is recommended. The reason for this is that due to how the reload
works there are some bizarre side-effects (like executing certain code mechanism works there are some bizarre side-effects (like executing
twice, sometimes crashing without message or dying when a syntax or certain code twice, sometimes crashing without message or dying when a
import error happens). syntax or import error happens).
It is however still a perfectly valid method for invoking a non automatic It is however still a perfectly valid method for invoking a non automatic
reloading application. reloading application.

2
docs/shell.rst

@ -29,7 +29,7 @@ chapter of the documentation first.
Command Line Interface Command Line Interface
---------------------- ----------------------
Starting with Flask 1.0 the recommended way to work with the shell is the Starting with Flask 0.11 the recommended way to work with the shell is the
``flask shell`` command which does a lot of this automatically for you. ``flask shell`` command which does a lot of this automatically for you.
For instance the shell is automatically initialized with a loaded For instance the shell is automatically initialized with a loaded
application context. application context.

6
docs/signals.rst

@ -19,9 +19,9 @@ more. Also keep in mind that signals are intended to notify subscribers
and should not encourage subscribers to modify data. You will notice that and should not encourage subscribers to modify data. You will notice that
there are signals that appear to do the same thing like some of the there are signals that appear to do the same thing like some of the
builtin decorators do (eg: :data:`~flask.request_started` is very similar builtin decorators do (eg: :data:`~flask.request_started` is very similar
to :meth:`~flask.Flask.before_request`). There are however difference in to :meth:`~flask.Flask.before_request`). However, there are differences in
how they work. The core :meth:`~flask.Flask.before_request` handler for how they work. The core :meth:`~flask.Flask.before_request` handler, for
example is executed in a specific order and is able to abort the request example, is executed in a specific order and is able to abort the request
early by returning a response. In contrast all signal handlers are early by returning a response. In contrast all signal handlers are
executed in undefined order and do not modify any data. executed in undefined order and do not modify any data.

2
docs/styleguide.rst

@ -167,7 +167,7 @@ Docstring conventions:
""" """
Module header: Module header:
The module header consists of an utf-8 encoding declaration (if non The module header consists of a utf-8 encoding declaration (if non
ASCII letters are used, but it is recommended all the time) and a ASCII letters are used, but it is recommended all the time) and a
standard docstring:: standard docstring::

32
docs/testing.rst

@ -24,7 +24,7 @@ the :ref:`tutorial`. If you don't have that application yet, get the
sources from `the examples`_. sources from `the examples`_.
.. _the examples: .. _the examples:
https://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ https://github.com/pallets/flask/tree/master/examples/flaskr/
The Testing Skeleton The Testing Skeleton
-------------------- --------------------
@ -33,7 +33,7 @@ In order to test the application, we add a second module
(:file:`flaskr_tests.py`) and create a unittest skeleton there:: (:file:`flaskr_tests.py`) and create a unittest skeleton there::
import os import os
import flaskr from flaskr import flaskr
import unittest import unittest
import tempfile import tempfile
@ -41,7 +41,7 @@ In order to test the application, we add a second module
def setUp(self): def setUp(self):
self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
flaskr.app.config['TESTING'] = True flaskr.app.testing = True
self.app = flaskr.app.test_client() self.app = flaskr.app.test_client()
with flaskr.app.app_context(): with flaskr.app.app_context():
flaskr.init_db() flaskr.init_db()
@ -98,8 +98,10 @@ test method to our class, like this::
def setUp(self): def setUp(self):
self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
flaskr.app.testing = True
self.app = flaskr.app.test_client() self.app = flaskr.app.test_client()
flaskr.init_db() with flaskr.app.app_context():
flaskr.init_db()
def tearDown(self): def tearDown(self):
os.close(self.db_fd) os.close(self.db_fd)
@ -152,13 +154,13 @@ invalid credentials. Add this new test to the class::
def test_login_logout(self): def test_login_logout(self):
rv = self.login('admin', 'default') rv = self.login('admin', 'default')
assert 'You were logged in' in rv.data assert b'You were logged in' in rv.data
rv = self.logout() rv = self.logout()
assert 'You were logged out' in rv.data assert b'You were logged out' in rv.data
rv = self.login('adminx', 'default') rv = self.login('adminx', 'default')
assert 'Invalid username' in rv.data assert b'Invalid username' in rv.data
rv = self.login('admin', 'defaultx') rv = self.login('admin', 'defaultx')
assert 'Invalid password' in rv.data assert b'Invalid password' in rv.data
Test Adding Messages Test Adding Messages
-------------------- --------------------
@ -172,9 +174,9 @@ like this::
title='<Hello>', title='<Hello>',
text='<strong>HTML</strong> allowed here' text='<strong>HTML</strong> allowed here'
), follow_redirects=True) ), follow_redirects=True)
assert 'No entries here so far' not in rv.data assert b'No entries here so far' not in rv.data
assert '&lt;Hello&gt;' in rv.data assert b'&lt;Hello&gt;' in rv.data
assert '<strong>HTML</strong> allowed here' in rv.data assert b'<strong>HTML</strong> allowed here' in rv.data
Here we check that HTML is allowed in the text but not in the title, Here we check that HTML is allowed in the text but not in the title,
which is the intended behavior. which is the intended behavior.
@ -194,7 +196,7 @@ suite.
.. _MiniTwit Example: .. _MiniTwit Example:
https://github.com/mitsuhiko/flask/tree/master/examples/minitwit/ https://github.com/pallets/flask/tree/master/examples/minitwit/
Other Testing Tricks Other Testing Tricks
@ -208,7 +210,7 @@ temporarily. With this you can access the :class:`~flask.request`,
functions. Here is a full example that demonstrates this approach:: functions. Here is a full example that demonstrates this approach::
import flask import flask
app = flask.Flask(__name__) app = flask.Flask(__name__)
with app.test_request_context('/?name=Peter'): with app.test_request_context('/?name=Peter'):
@ -223,8 +225,8 @@ there does not seem to be a good way to do that, consider switching to
application factories (see :ref:`app-factories`). application factories (see :ref:`app-factories`).
Note however that if you are using a test request context, the Note however that if you are using a test request context, the
:meth:`~flask.Flask.before_request` functions are not automatically called :meth:`~flask.Flask.before_request` and :meth:`~flask.Flask.after_request`
same for :meth:`~flask.Flask.after_request` functions. However functions are not called automatically. However
:meth:`~flask.Flask.teardown_request` functions are indeed executed when :meth:`~flask.Flask.teardown_request` functions are indeed executed when
the test request context leaves the ``with`` block. If you do want the the test request context leaves the ``with`` block. If you do want the
:meth:`~flask.Flask.before_request` functions to be called as well, you :meth:`~flask.Flask.before_request` functions to be called as well, you

4
docs/tutorial/css.rst

@ -1,11 +1,11 @@
.. _tutorial-css: .. _tutorial-css:
Step 7: Adding Style Step 8: Adding Style
==================== ====================
Now that everything else works, it's time to add some style to the Now that everything else works, it's time to add some style to the
application. Just create a stylesheet called :file:`style.css` in the application. Just create a stylesheet called :file:`style.css` in the
:file:`static` folder we created before: :file:`static` folder:
.. sourcecode:: css .. sourcecode:: css

31
docs/tutorial/dbcon.rst

@ -1,25 +1,23 @@
.. _tutorial-dbcon: .. _tutorial-dbcon:
Step 3: Database Connections Step 4: Database Connections
---------------------------- ----------------------------
We have created a function for establishing a database connection with You currently have a function for establishing a database connection with
`connect_db`, but by itself, that's not particularly useful. Creating and `connect_db`, but by itself, it is not particularly useful. Creating and
closing database connections all the time is very inefficient, so we want closing database connections all the time is very inefficient, so you will
to keep it around for longer. Because database connections encapsulate a need to keep it around for longer. Because database connections
transaction, we also need to make sure that only one request at the time encapsulate a transaction, you will need to make sure that only one
uses the connection. How can we elegantly do that with Flask? request at a time uses the connection. An elegant way to do this is by
utilizing the *application context*.
This is where the application context comes into play, so let's start Flask provides two contexts: the *application context* and the
there. *request context*. For the time being, all you have to know is that there
Flask provides us with two contexts: the application context and the
request context. For the time being, all you have to know is that there
are special variables that use these. For instance, the are special variables that use these. For instance, the
:data:`~flask.request` variable is the request object associated with :data:`~flask.request` variable is the request object associated with
the current request, whereas :data:`~flask.g` is a general purpose the current request, whereas :data:`~flask.g` is a general purpose
variable associated with the current application context. We will go into variable associated with the current application context. The tutorial
the details of this a bit later. will cover some more details of this later on.
For the time being, all you have to know is that you can store information For the time being, all you have to know is that you can store information
safely on the :data:`~flask.g` object. safely on the :data:`~flask.g` object.
@ -37,8 +35,7 @@ already established connection::
g.sqlite_db = connect_db() g.sqlite_db = connect_db()
return g.sqlite_db return g.sqlite_db
Now you know how to connect, but how can you properly disconnect? For
So now we know how to connect, but how do we properly disconnect? For
that, Flask provides us with the :meth:`~flask.Flask.teardown_appcontext` that, Flask provides us with the :meth:`~flask.Flask.teardown_appcontext`
decorator. It's executed every time the application context tears down:: decorator. It's executed every time the application context tears down::
@ -75,4 +72,4 @@ Continue to :ref:`tutorial-dbinit`.
larger <larger-applications>`, it's a good idea not to. larger <larger-applications>`, it's a good idea not to.
.. _example source: .. _example source:
https://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ https://github.com/pallets/flask/tree/master/examples/flaskr/

33
docs/tutorial/dbinit.rst

@ -1,6 +1,6 @@
.. _tutorial-dbinit: .. _tutorial-dbinit:
Step 4: Creating The Database Step 5: Creating The Database
============================= =============================
As outlined earlier, Flaskr is a database powered application, and more As outlined earlier, Flaskr is a database powered application, and more
@ -16,13 +16,14 @@ Such a schema can be created by piping the ``schema.sql`` file into the
The downside of this is that it requires the ``sqlite3`` command to be The downside of this is that it requires the ``sqlite3`` command to be
installed, which is not necessarily the case on every system. This also installed, which is not necessarily the case on every system. This also
requires that we provide the path to the database, which can introduce requires that you provide the path to the database, which can introduce
errors. It's a good idea to add a function that initializes the database errors. It's a good idea to add a function that initializes the database
for you to the application. for you, to the application.
To do this, we can create a function and hook it into the :command:`flask` To do this, you can create a function and hook it into a :command:`flask`
command that initializes the database. Let me show you the code first. Just command that initializes the database. For now just take a look at the
add this function below the `connect_db` function in :file:`flaskr.py`:: code segment below. A good place to add this function, and command, is
just below the `connect_db` function in :file:`flaskr.py`::
def init_db(): def init_db():
db = get_db() db = get_db()
@ -34,33 +35,33 @@ add this function below the `connect_db` function in :file:`flaskr.py`::
def initdb_command(): def initdb_command():
"""Initializes the database.""" """Initializes the database."""
init_db() init_db()
print 'Initialized the database.' print('Initialized the database.')
The ``app.cli.command()`` decorator registers a new command with the The ``app.cli.command()`` decorator registers a new command with the
:command:`flask` script. When the command executes, Flask will automatically :command:`flask` script. When the command executes, Flask will automatically
create a application context for us bound to the right application. create an application context which is bound to the right application.
Within the function, we can then access :attr:`flask.g` and other things as Within the function, you can then access :attr:`flask.g` and other things as
we would expect. When the script ends, the application context tears down you might expect. When the script ends, the application context tears down
and the database connection is released. and the database connection is released.
We want to keep an actual functions around that initializes the database, You will want to keep an actual function around that initializes the database,
though, so that we can easily create databases in unit tests later on. (For though, so that we can easily create databases in unit tests later on. (For
more information see :ref:`testing`.) more information see :ref:`testing`.)
The :func:`~flask.Flask.open_resource` method of the application object The :func:`~flask.Flask.open_resource` method of the application object
is a convenient helper function that will open a resource that the is a convenient helper function that will open a resource that the
application provides. This function opens a file from the resource application provides. This function opens a file from the resource
location (your ``flaskr`` folder) and allows you to read from it. We are location (the :file:`flaskr/flaskr` folder) and allows you to read from it.
using this here to execute a script on the database connection. It is used in this example to execute a script on the database connection.
The connection object provided by SQLite can give us a cursor object. The connection object provided by SQLite can give you a cursor object.
On that cursor, there is a method to execute a complete script. Finally, we On that cursor, there is a method to execute a complete script. Finally, you
only have to commit the changes. SQLite3 and other transactional only have to commit the changes. SQLite3 and other transactional
databases will not commit unless you explicitly tell it to. databases will not commit unless you explicitly tell it to.
Now, it is possible to create a database with the :command:`flask` script:: Now, it is possible to create a database with the :command:`flask` script::
flask --app=flaskr initdb flask initdb
Initialized the database. Initialized the database.
.. admonition:: Troubleshooting .. admonition:: Troubleshooting

26
docs/tutorial/folders.rst

@ -3,21 +3,25 @@
Step 0: Creating The Folders Step 0: Creating The Folders
============================ ============================
Before we get started, let's create the folders needed for this Before getting started, you will need to create the folders needed for this
application:: application::
/flaskr /flaskr
/static /flaskr
/templates /static
/templates
The ``flaskr`` folder is not a Python package, but just something where we The application will be installed and run as Python package. This is the
drop our files. Later on, we will put our database schema as well as main recommended way to install and run Flask applications. You will see exactly
module into this folder. It is done in the following way. The files inside how to run ``flaskr`` later on in this tutorial. For now go ahead and create
the :file:`static` folder are available to users of the application via HTTP. the applications directory structure. In the next few steps you will be
This is the place where CSS and Javascript files go. Inside the creating the database schema as well as the main module.
:file:`templates` folder, Flask will look for `Jinja2`_ templates. The
templates you create later on in the tutorial will go in this directory.
Continue with :ref:`tutorial-schema`. As a quick side note, the files inside of the :file:`static` folder are
available to users of the application via HTTP. This is the place where CSS and
JavaScript files go. Inside the :file:`templates` folder, Flask will look for
`Jinja2`_ templates. You will see examples of this later on.
For now you should continue with :ref:`tutorial-schema`.
.. _Jinja2: http://jinja.pocoo.org/ .. _Jinja2: http://jinja.pocoo.org/

3
docs/tutorial/index.rst

@ -15,7 +15,7 @@ If you want the full source code in advance or for comparison, check out
the `example source`_. the `example source`_.
.. _example source: .. _example source:
https://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ https://github.com/pallets/flask/tree/master/examples/flaskr/
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
@ -24,6 +24,7 @@ the `example source`_.
folders folders
schema schema
setup setup
packaging
dbcon dbcon
dbinit dbinit
views views

11
docs/tutorial/introduction.rst

@ -3,8 +3,9 @@
Introducing Flaskr Introducing Flaskr
================== ==================
We will call our blogging application flaskr, but feel free to choose your own This tutorial will demonstrate a blogging application named Flaskr, but feel
less Web-2.0-ish name ;) Essentially, we want it to do the following things: free to choose your own less Web-2.0-ish name ;) Essentially, it will do the
following things:
1. Let the user sign in and out with credentials specified in the 1. Let the user sign in and out with credentials specified in the
configuration. Only one user is supported. configuration. Only one user is supported.
@ -14,8 +15,8 @@ less Web-2.0-ish name ;) Essentially, we want it to do the following things:
3. The index page shows all entries so far in reverse chronological order 3. The index page shows all entries so far in reverse chronological order
(newest on top) and the user can add new ones from there if logged in. (newest on top) and the user can add new ones from there if logged in.
We will be using SQLite3 directly for this application because it's good SQLite3 will be used directly for this application because it's good enough
enough for an application of this size. For larger applications, however, for an application of this size. For larger applications, however,
it makes a lot of sense to use `SQLAlchemy`_, as it handles database it makes a lot of sense to use `SQLAlchemy`_, as it handles database
connections in a more intelligent way, allowing you to target different connections in a more intelligent way, allowing you to target different
relational databases at once and more. You might also want to consider relational databases at once and more. You might also want to consider
@ -30,4 +31,4 @@ Here a screenshot of the final application:
Continue with :ref:`tutorial-folders`. Continue with :ref:`tutorial-folders`.
.. _SQLAlchemy: http://www.sqlalchemy.org/ .. _SQLAlchemy: https://www.sqlalchemy.org/

108
docs/tutorial/packaging.rst

@ -0,0 +1,108 @@
.. _tutorial-packaging:
Step 3: Installing flaskr as a Package
======================================
Flask is now shipped with built-in support for `Click`_. Click provides
Flask with enhanced and extensible command line utilities. Later in this
tutorial you will see exactly how to extend the ``flask`` command line
interface (CLI).
A useful pattern to manage a Flask application is to install your app
following the `Python Packaging Guide`_. Presently this involves
creating two new files; :file:`setup.py` and :file:`MANIFEST.in` in the
projects root directory. You also need to add an :file:`__init__.py`
file to make the :file:`flaskr/flaskr` directory a package. After these
changes, your code structure should be::
/flaskr
/flaskr
__init__.py
/static
/templates
flaskr.py
schema.sql
setup.py
MANIFEST.in
The content of the ``setup.py`` file for ``flaskr`` is:
.. sourcecode:: python
from setuptools import setup
setup(
name='flaskr',
packages=['flaskr'],
include_package_data=True,
install_requires=[
'flask',
],
)
When using setuptools, it is also necessary to specify any special files
that should be included in your package (in the :file:`MANIFEST.in`).
In this case, the static and templates directories need to be included,
as well as the schema. Create the :file:`MANIFEST.in` and add the
following lines::
graft flaskr/templates
graft flaskr/static
include flaskr/schema.sql
To simplify locating the application, add the following import statement
into this file, :file:`flaskr/__init__.py`:
.. sourcecode:: python
from .flaskr import app
This import statement brings the application instance into the top-level
of the application package. When it is time to run the application, the
Flask development server needs the location of the app instance. This
import statement simplifies the location process. Without it the export
statement a few steps below would need to be
``export FLASK_APP=flaskr.flaskr``.
At this point you should be able to install the application. As usual, it
is recommended to install your Flask application within a `virtualenv`_.
With that said, go ahead and install the application with::
pip install --editable .
The above installation command assumes that it is run within the projects
root directory, `flaskr/`. The `editable` flag allows editing
source code without having to reinstall the Flask app each time you make
changes. The flaskr app is now installed in your virtualenv (see output
of ``pip freeze``).
With that out of the way, you should be able to start up the application.
Do this with the following commands::
export FLASK_APP=flaskr
export FLASK_DEBUG=true
flask run
(In case you are on Windows you need to use `set` instead of `export`).
The :envvar:`FLASK_DEBUG` flag enables or disables the interactive debugger.
*Never leave debug mode activated in a production system*, because it will
allow users to execute code on the server!
You will see a message telling you that server has started along with
the address at which you can access it.
When you head over to the server in your browser, you will get a 404 error
because we don't have any views yet. That will be addressed a little later,
but first, you should get the database working.
.. admonition:: Externally Visible Server
Want your server to be publicly available? Check out the
:ref:`externally visible server <public-server>` section for more
information.
Continue with :ref:`tutorial-dbcon`.
.. _Click: http://click.pocoo.org
.. _Python Packaging Guide: https://packaging.python.org
.. _virtualenv: https://virtualenv.pypa.io

10
docs/tutorial/schema.rst

@ -3,10 +3,10 @@
Step 1: Database Schema Step 1: Database Schema
======================= =======================
First, we want to create the database schema. Only a single table is needed In this step, you will create the database schema. Only a single table is
for this application and we only want to support SQLite, so creating the needed for this application and it will only support SQLite. All you need to do
database schema is quite easy. Just put the following contents into a file is put the following contents into a file named :file:`schema.sql` in the
named `schema.sql` in the just created `flaskr` folder: :file:`flaskr/flaskr` folder:
.. sourcecode:: sql .. sourcecode:: sql
@ -17,7 +17,7 @@ named `schema.sql` in the just created `flaskr` folder:
'text' text not null 'text' text not null
); );
This schema consists of a single table called ``entries``. Each row in This schema consists of a single table called ``entries``. Each row in
this table has an ``id``, a ``title``, and a ``text``. The ``id`` is an this table has an ``id``, a ``title``, and a ``text``. The ``id`` is an
automatically incrementing integer and a primary key, the other two are automatically incrementing integer and a primary key, the other two are
strings that must not be null. strings that must not be null.

70
docs/tutorial/setup.rst

@ -3,15 +3,16 @@
Step 2: Application Setup Code Step 2: Application Setup Code
============================== ==============================
Now that we have the schema in place, we can create the application module. Now that the schema is in place, you can create the application module,
Let's call it ``flaskr.py``. We will place this file inside the ``flaskr`` :file:`flaskr.py`. This file should be placed inside of the
folder. We will begin by adding the imports we need and by adding the config :file:`flaskr/flaskr` folder. The first several lines of code in the
section. For small applications, it is possible to drop the configuration application module are the needed import statements. After that there will be a
directly into the module, and this is what we will be doing here. However, few lines of configuration code. For small applications like ``flaskr``, it is
a cleaner solution would be to create a separate ``.ini`` or ``.py`` file, possible to drop the configuration directly into the module. However, a cleaner
load that, and import the values from there. solution is to create a separate ``.ini`` or ``.py`` file, load that, and
import the values from there.
First, we add the imports in :file:`flaskr.py`:: Here are the import statements (in :file:`flaskr.py`)::
# all the imports # all the imports
import os import os
@ -19,12 +20,13 @@ First, we add the imports in :file:`flaskr.py`::
from flask import Flask, request, session, g, redirect, url_for, abort, \ from flask import Flask, request, session, g, redirect, url_for, abort, \
render_template, flash render_template, flash
Next, we can create our actual application and initialize it with the The next couple lines will create the actual application instance and
config from the same file in :file:`flaskr.py`:: initialize it with the config from the same file in :file:`flaskr.py`:
# create our little application :) .. sourcecode:: python
app = Flask(__name__)
app.config.from_object(__name__) app = Flask(__name__) # create the application instance :)
app.config.from_object(__name__) # load config from this file , flaskr.py
# Load default config and override config from an environment variable # Load default config and override config from an environment variable
app.config.update(dict( app.config.update(dict(
@ -35,8 +37,8 @@ config from the same file in :file:`flaskr.py`::
)) ))
app.config.from_envvar('FLASKR_SETTINGS', silent=True) app.config.from_envvar('FLASKR_SETTINGS', silent=True)
The :class:`~flask.Config` object works similarly to a dictionary so we The :class:`~flask.Config` object works similarly to a dictionary, so it can be
can update it with new values. updated with new values.
.. admonition:: Database Path .. admonition:: Database Path
@ -55,10 +57,10 @@ can update it with new values.
Usually, it is a good idea to load a separate, environment-specific Usually, it is a good idea to load a separate, environment-specific
configuration file. Flask allows you to import multiple configurations and it configuration file. Flask allows you to import multiple configurations and it
will use the setting defined in the last import. This enables robust will use the setting defined in the last import. This enables robust
configuration setups. :meth:`~flask.Config.from_envvar` can help achieve this. configuration setups. :meth:`~flask.Config.from_envvar` can help achieve this.
.. code-block:: python .. sourcecode:: python
app.config.from_envvar('FLASKR_SETTINGS', silent=True) app.config.from_envvar('FLASKR_SETTINGS', silent=True)
@ -74,15 +76,15 @@ that in all cases, only variable names that are uppercase are considered.
The ``SECRET_KEY`` is needed to keep the client-side sessions secure. The ``SECRET_KEY`` is needed to keep the client-side sessions secure.
Choose that key wisely and as hard to guess and complex as possible. Choose that key wisely and as hard to guess and complex as possible.
We will also add a method that allows for easy connections to the Lastly, you will add a method that allows for easy connections to the
specified database. This can be used to open a connection on request and specified database. This can be used to open a connection on request and
also from the interactive Python shell or a script. This will come in also from the interactive Python shell or a script. This will come in
handy later. We create a simple database connection through SQLite and handy later. You can create a simple database connection through SQLite and
then tell it to use the :class:`sqlite3.Row` object to represent rows. then tell it to use the :class:`sqlite3.Row` object to represent rows.
This allows us to treat the rows as if they were dictionaries instead of This allows the rows to be treated as if they were dictionaries instead of
tuples. tuples.
:: .. sourcecode:: python
def connect_db(): def connect_db():
"""Connects to the specific database.""" """Connects to the specific database."""
@ -90,26 +92,6 @@ tuples.
rv.row_factory = sqlite3.Row rv.row_factory = sqlite3.Row
return rv return rv
With that out of the way, you should be able to start up the application In the next section you will see how to run the application.
without problems. Do this with the following command::
flask --app=flaskr --debug run
The :option:`--debug` flag enables or disables the interactive debugger. *Never
leave debug mode activated in a production system*, because it will allow
users to execute code on the server!
You will see a message telling you that server has started along with
the address at which you can access it.
When you head over to the server in your browser, you will get a 404 error
because we don't have any views yet. We will focus on that a little later,
but first, we should get the database working.
.. admonition:: Externally Visible Server
Want your server to be publicly available? Check out the
:ref:`externally visible server <public-server>` section for more
information.
Continue with :ref:`tutorial-dbcon`. Continue with :ref:`tutorial-packaging`.

19
docs/tutorial/templates.rst

@ -1,11 +1,12 @@
.. _tutorial-templates: .. _tutorial-templates:
Step 6: The Templates Step 7: The Templates
===================== =====================
Now we should start working on the templates. If we were to request the URLs Now it is time to start working on the templates. As you may have
now, we would only get an exception that Flask cannot find the templates. The noticed, if you make requests with the app running, you will get
templates are using `Jinja2`_ syntax and have autoescaping enabled by an exception that Flask cannot find the templates. The templates
are using `Jinja2`_ syntax and have autoescaping enabled by
default. This means that unless you mark a value in the code with default. This means that unless you mark a value in the code with
:class:`~flask.Markup` or with the ``|safe`` filter in the template, :class:`~flask.Markup` or with the ``|safe`` filter in the template,
Jinja2 will ensure that special characters such as ``<`` or ``>`` are Jinja2 will ensure that special characters such as ``<`` or ``>`` are
@ -57,9 +58,9 @@ show_entries.html
This template extends the :file:`layout.html` template from above to display the This template extends the :file:`layout.html` template from above to display the
messages. Note that the ``for`` loop iterates over the messages we passed messages. Note that the ``for`` loop iterates over the messages we passed
in with the :func:`~flask.render_template` function. We also tell the in with the :func:`~flask.render_template` function. Notice that the form is
form to submit to your `add_entry` function and use ``POST`` as HTTP configured to submit to the `add_entry` view function and use ``POST`` as
method: HTTP method:
.. sourcecode:: html+jinja .. sourcecode:: html+jinja
@ -78,9 +79,9 @@ method:
{% endif %} {% endif %}
<ul class=entries> <ul class=entries>
{% for entry in entries %} {% for entry in entries %}
<li><h2>{{ entry.title }}</h2>{{ entry.text|safe }} <li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}</li>
{% else %} {% else %}
<li><em>Unbelievable. No entries here so far</em> <li><em>Unbelievable. No entries here so far</em></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endblock %} {% endblock %}

86
docs/tutorial/testing.rst

@ -8,3 +8,89 @@ expected, it's probably not a bad idea to add automated tests to simplify
modifications in the future. The application above is used as a basic modifications in the future. The application above is used as a basic
example of how to perform unit testing in the :ref:`testing` section of the example of how to perform unit testing in the :ref:`testing` section of the
documentation. Go there to see how easy it is to test Flask applications. documentation. Go there to see how easy it is to test Flask applications.
Adding tests to flaskr
----------------------
Assuming you have seen the :ref:`testing` section and have either written
your own tests for ``flaskr`` or have followed along with the examples
provided, you might be wondering about ways to organize the project.
One possible and recommended project structure is::
flaskr/
flaskr/
__init__.py
static/
templates/
tests/
test_flaskr.py
setup.py
MANIFEST.in
For now go ahead a create the :file:`tests/` directory as well as the
:file:`test_flaskr.py` file.
Running the tests
-----------------
At this point you can run the tests. Here ``pytest`` will be used.
.. note:: Make sure that ``pytest`` is installed in the same virtualenv
as flaskr. Otherwise ``pytest`` test will not be able to import the
required components to test the application::
pip install -e .
pip install pytest
Run and watch the tests pass, within the top-level :file:`flaskr/`
directory as::
pytest
Testing + setuptools
--------------------
One way to handle testing is to integrate it with ``setuptools``. Here
that requires adding a couple of lines to the :file:`setup.py` file and
creating a new file :file:`setup.cfg`. One benefit of running the tests
this way is that you do not have to install ``pytest``. Go ahead and
update the :file:`setup.py` file to contain::
from setuptools import setup
setup(
name='flaskr',
packages=['flaskr'],
include_package_data=True,
install_requires=[
'flask',
],
setup_requires=[
'pytest-runner',
],
tests_require=[
'pytest',
],
)
Now create :file:`setup.cfg` in the project root (alongside
:file:`setup.py`)::
[aliases]
test=pytest
Now you can run::
python setup.py test
This calls on the alias created in :file:`setup.cfg` which in turn runs
``pytest`` via ``pytest-runner``, as the :file:`setup.py` script has
been called. (Recall the `setup_requires` argument in :file:`setup.py`)
Following the standard rules of test-discovery your tests will be
found, run, and hopefully pass.
This is one possible way to run and manage testing. Here ``pytest`` is
used, but there are other options such as ``nose``. Integrating testing
with ``setuptools`` is convenient because it is not necessary to actually
download ``pytest`` or any other testing framework one might use.

43
docs/tutorial/views.rst

@ -1,10 +1,10 @@
.. _tutorial-views: .. _tutorial-views:
Step 5: The View Functions Step 6: The View Functions
========================== ==========================
Now that the database connections are working, we can start writing the Now that the database connections are working, you can start writing the
view functions. We will need four of them: view functions. You will need four of them:
Show Entries Show Entries
------------ ------------
@ -12,11 +12,11 @@ Show Entries
This view shows all the entries stored in the database. It listens on the This view shows all the entries stored in the database. It listens on the
root of the application and will select title and text from the database. root of the application and will select title and text from the database.
The one with the highest id (the newest entry) will be on top. The rows The one with the highest id (the newest entry) will be on top. The rows
returned from the cursor look a bit like tuples because we are using returned from the cursor look a bit like dictionaries because we are using
the :class:`sqlite3.Row` row factory. the :class:`sqlite3.Row` row factory.
The view function will pass the entries as dictionaries to the The view function will pass the entries to the :file:`show_entries.html`
:file:`show_entries.html` template and return the rendered one:: template and return the rendered one::
@app.route('/') @app.route('/')
def show_entries(): def show_entries():
@ -30,7 +30,7 @@ Add New Entry
This view lets the user add new entries if they are logged in. This only This view lets the user add new entries if they are logged in. This only
responds to ``POST`` requests; the actual form is shown on the responds to ``POST`` requests; the actual form is shown on the
`show_entries` page. If everything worked out well, we will `show_entries` page. If everything worked out well, it will
:func:`~flask.flash` an information message to the next request and :func:`~flask.flash` an information message to the next request and
redirect back to the `show_entries` page:: redirect back to the `show_entries` page::
@ -45,8 +45,8 @@ redirect back to the `show_entries` page::
flash('New entry was successfully posted') flash('New entry was successfully posted')
return redirect(url_for('show_entries')) return redirect(url_for('show_entries'))
Note that we check that the user is logged in here (the `logged_in` key is Note that this view checks that the user is logged in (that is, if the
present in the session and ``True``). `logged_in` key is present in the session and ``True``).
.. admonition:: Security Note .. admonition:: Security Note
@ -81,11 +81,11 @@ notified about that, and the user is asked again::
return render_template('login.html', error=error) return render_template('login.html', error=error)
The `logout` function, on the other hand, removes that key from the session The `logout` function, on the other hand, removes that key from the session
again. We use a neat trick here: if you use the :meth:`~dict.pop` method again. There is a neat trick here: if you use the :meth:`~dict.pop` method
of the dict and pass a second parameter to it (the default), the method of the dict and pass a second parameter to it (the default), the method
will delete the key from the dictionary if present or do nothing when that will delete the key from the dictionary if present or do nothing when that
key is not in there. This is helpful because now we don't have to check key is not in there. This is helpful because now it is not necessary to
if the user was logged in. check if the user was logged in.
:: ::
@ -95,4 +95,23 @@ if the user was logged in.
flash('You were logged out') flash('You were logged out')
return redirect(url_for('show_entries')) return redirect(url_for('show_entries'))
.. admonition:: Security Note
Passwords should never be stored in plain text in a production
system. This tutorial uses plain text passwords for simplicity. If you
plan to release a project based off this tutorial out into the world,
passwords should be both `hashed and salted`_ before being stored in a
database or file.
Fortunately, there are Flask extensions for the purpose of
hashing passwords and verifying passwords against hashes, so adding
this functionality is fairly straight forward. There are also
many general python libraries that can be used for hashing.
You can find a list of recommended Flask extensions
`here <http://flask.pocoo.org/extensions/>`_
Continue with :ref:`tutorial-templates`. Continue with :ref:`tutorial-templates`.
.. _hashed and salted: https://blog.codinghorror.com/youre-probably-storing-passwords-incorrectly/

113
docs/upgrading.rst

@ -14,21 +14,75 @@ This section of the documentation enumerates all the changes in Flask from
release to release and how you can change your code to have a painless release to release and how you can change your code to have a painless
updating experience. updating experience.
If you want to use the :command:`easy_install` command to upgrade your Flask Use the :command:`pip` command to upgrade your existing Flask installation by
installation, make sure to pass it the :option:`-U` parameter:: providing the ``--upgrade`` parameter::
$ easy_install -U Flask $ pip install --upgrade Flask
.. _upgrading-to-10: .. _upgrading-to-012:
Version 1.0 Version 0.12
----------- ------------
Changes to send_file
````````````````````
The ``filename`` is no longer automatically inferred from file-like objects.
This means that the following code will no longer automatically have
``X-Sendfile`` support, etag generation or MIME-type guessing::
response = send_file(open('/path/to/file.txt'))
Any of the following is functionally equivalent::
fname = '/path/to/file.txt'
# Just pass the filepath directly
response = send_file(fname)
# Set the MIME-type and ETag explicitly
response = send_file(open(fname), mimetype='text/plain')
response.set_etag(...)
# Set `attachment_filename` for MIME-type guessing
# ETag still needs to be manually set
response = send_file(open(fname), attachment_filename=fname)
response.set_etag(...)
The reason for this is that some file-like objects have an invalid or even
misleading ``name`` attribute. Silently swallowing errors in such cases was not
a satisfying solution.
Additionally the default of falling back to ``application/octet-stream`` has
been restricted. If Flask can't guess one or the user didn't provide one, the
function fails if no filename information was provided.
.. _upgrading-to-011:
Version 0.11
------------
0.11 is an odd release in the Flask release cycle because it was supposed
to be the 1.0 release. However because there was such a long lead time up
to the release we decided to push out a 0.11 release first with some
changes removed to make the transition easier. If you have been tracking
the master branch which was 1.0 you might see some unexpected changes.
Flask 1.0 removed the ``debug_log_format`` attribute from Flask In case you did track the master branch you will notice that :command:`flask --app`
is removed now. You need to use the environment variable to specify an
application.
Debugging
`````````
Flask 0.11 removed the ``debug_log_format`` attribute from Flask
applications. Instead the new ``LOGGER_HANDLER_POLICY`` configuration can applications. Instead the new ``LOGGER_HANDLER_POLICY`` configuration can
be used to disable the default log handlers and custom log handlers can be be used to disable the default log handlers and custom log handlers can be
set up. set up.
Error handling
``````````````
The behavior of error handlers was changed. The behavior of error handlers was changed.
The precedence of handlers used to be based on the decoration/call order of The precedence of handlers used to be based on the decoration/call order of
:meth:`~flask.Flask.errorhandler` and :meth:`~flask.Flask.errorhandler` and
@ -37,9 +91,7 @@ Now the inheritance hierarchy takes precedence and handlers for more
specific exception classes are executed instead of more general ones. specific exception classes are executed instead of more general ones.
See :ref:`error-handlers` for specifics. See :ref:`error-handlers` for specifics.
The :func:`~flask.templating.render_template_string` function has changed to Trying to register a handler on an instance now raises :exc:`ValueError`.
autoescape template variables by default. This better matches the behavior
of :func:`~flask.templating.render_template`.
.. note:: .. note::
@ -47,8 +99,25 @@ of :func:`~flask.templating.render_template`.
only for exception *instances*. This was unintended and plain wrong, only for exception *instances*. This was unintended and plain wrong,
and therefore was replaced with the intended behavior of registering and therefore was replaced with the intended behavior of registering
handlers only using exception classes and HTTP error codes. handlers only using exception classes and HTTP error codes.
Trying to register a handler on an instance now raises :exc:`ValueError`. Templating
``````````
The :func:`~flask.templating.render_template_string` function has changed to
autoescape template variables by default. This better matches the behavior
of :func:`~flask.templating.render_template`.
Extension imports
`````````````````
Extension imports of the form ``flask.ext.foo`` are deprecated, you should use
``flask_foo``.
The old form still works, but Flask will issue a
``flask.exthook.ExtDeprecationWarning`` for each extension you import the old
way. We also provide a migration utility called `flask-ext-migrate
<https://github.com/pallets/flask-ext-migrate>`_ that is supposed to
automatically rewrite your imports for this.
.. _upgrading-to-010: .. _upgrading-to-010:
@ -74,7 +143,7 @@ when there is no request context yet but an application context. The old
``flask.Flask.request_globals_class`` attribute was renamed to ``flask.Flask.request_globals_class`` attribute was renamed to
:attr:`flask.Flask.app_ctx_globals_class`. :attr:`flask.Flask.app_ctx_globals_class`.
.. _Flask-OldSessions: http://pythonhosted.org/Flask-OldSessions/ .. _Flask-OldSessions: https://pythonhosted.org/Flask-OldSessions/
Version 0.9 Version 0.9
----------- -----------
@ -102,7 +171,7 @@ Version 0.8
----------- -----------
Flask introduced a new session interface system. We also noticed that Flask introduced a new session interface system. We also noticed that
there was a naming collision between `flask.session` the module that there was a naming collision between ``flask.session`` the module that
implements sessions and :data:`flask.session` which is the global session implements sessions and :data:`flask.session` which is the global session
object. With that introduction we moved the implementation details for object. With that introduction we moved the implementation details for
the session system into a new module called :mod:`flask.sessions`. If you the session system into a new module called :mod:`flask.sessions`. If you
@ -129,7 +198,7 @@ applications with Flask. Because we want to make upgrading as easy as
possible we tried to counter the problems arising from these changes by possible we tried to counter the problems arising from these changes by
providing a script that can ease the transition. providing a script that can ease the transition.
The script scans your whole application and generates an unified diff with The script scans your whole application and generates a unified diff with
changes it assumes are safe to apply. However as this is an automated changes it assumes are safe to apply. However as this is an automated
tool it won't be able to find all use cases and it might miss some. We tool it won't be able to find all use cases and it might miss some. We
internally spread a lot of deprecation warnings all over the place to make internally spread a lot of deprecation warnings all over the place to make
@ -146,7 +215,7 @@ good.
To apply the upgrade script do the following: To apply the upgrade script do the following:
1. Download the script: `flask-07-upgrade.py 1. Download the script: `flask-07-upgrade.py
<https://raw.githubusercontent.com/mitsuhiko/flask/master/scripts/flask-07-upgrade.py>`_ <https://raw.githubusercontent.com/pallets/flask/master/scripts/flask-07-upgrade.py>`_
2. Run it in the directory of your application:: 2. Run it in the directory of your application::
python flask-07-upgrade.py > patchfile.diff python flask-07-upgrade.py > patchfile.diff
@ -168,7 +237,7 @@ Please note that deprecation warnings are disabled by default starting
with Python 2.7. In order to see the deprecation warnings that might be with Python 2.7. In order to see the deprecation warnings that might be
emitted you have to enabled them with the :mod:`warnings` module. emitted you have to enabled them with the :mod:`warnings` module.
If you are working with windows and you lack the `patch` command line If you are working with windows and you lack the ``patch`` command line
utility you can get it as part of various Unix runtime environments for utility you can get it as part of various Unix runtime environments for
windows including cygwin, msysgit or ming32. Also source control systems windows including cygwin, msysgit or ming32. Also source control systems
like svn, hg or git have builtin support for applying unified diffs as like svn, hg or git have builtin support for applying unified diffs as
@ -185,7 +254,7 @@ before, you should catch them with :exc:`RuntimeError` now.
Additionally the :func:`~flask.send_file` function is now issuing Additionally the :func:`~flask.send_file` function is now issuing
deprecation warnings if you depend on functionality that will be removed deprecation warnings if you depend on functionality that will be removed
in Flask 1.0. Previously it was possible to use etags and mimetypes in Flask 0.11. Previously it was possible to use etags and mimetypes
when file objects were passed. This was unreliable and caused issues when file objects were passed. This was unreliable and caused issues
for a few setups. If you get a deprecation warning, make sure to for a few setups. If you get a deprecation warning, make sure to
update your application to work with either filenames there or disable update your application to work with either filenames there or disable
@ -285,7 +354,7 @@ to upgrade. What changed?
runtime. runtime.
- Blueprints have an inverse behavior for :meth:`url_for`. Previously - Blueprints have an inverse behavior for :meth:`url_for`. Previously
``.foo`` told :meth:`url_for` that it should look for the endpoint ``.foo`` told :meth:`url_for` that it should look for the endpoint
`foo` on the application. Now it means “relative to current module”. ``foo`` on the application. Now it means “relative to current module”.
The script will inverse all calls to :meth:`url_for` automatically for The script will inverse all calls to :meth:`url_for` automatically for
you. It will do this in a very eager way so you might end up with you. It will do this in a very eager way so you might end up with
some unnecessary leading dots in your code if you're not using some unnecessary leading dots in your code if you're not using
@ -303,7 +372,7 @@ to upgrade. What changed?
name into that folder if you want :file:`blueprintname/template.html` as name into that folder if you want :file:`blueprintname/template.html` as
the template name. the template name.
If you continue to use the `Module` object which is deprecated, Flask will If you continue to use the ``Module`` object which is deprecated, Flask will
restore the previous behavior as good as possible. However we strongly restore the previous behavior as good as possible. However we strongly
recommend upgrading to the new blueprints as they provide a lot of useful recommend upgrading to the new blueprints as they provide a lot of useful
improvement such as the ability to attach a blueprint multiple times, improvement such as the ability to attach a blueprint multiple times,
@ -323,7 +392,7 @@ change the order.
Another change that breaks backwards compatibility is that context Another change that breaks backwards compatibility is that context
processors will no longer override values passed directly to the template processors will no longer override values passed directly to the template
rendering function. If for example `request` is as variable passed rendering function. If for example ``request`` is as variable passed
directly to the template, the default context processor will not override directly to the template, the default context processor will not override
it with the current request object. This makes it easier to extend it with the current request object. This makes it easier to extend
context processors later to inject additional variables without breaking context processors later to inject additional variables without breaking
@ -349,7 +418,7 @@ The following changes may be relevant to your application:
for this feature. Removing support for this makes the Flask internal for this feature. Removing support for this makes the Flask internal
code easier to understand and fixes a couple of small issues that make code easier to understand and fixes a couple of small issues that make
debugging harder than necessary. debugging harder than necessary.
- The `create_jinja_loader` function is gone. If you want to customize - The ``create_jinja_loader`` function is gone. If you want to customize
the Jinja loader now, use the the Jinja loader now, use the
:meth:`~flask.Flask.create_jinja_environment` method instead. :meth:`~flask.Flask.create_jinja_environment` method instead.

1
examples/flaskr/.gitignore vendored

@ -1 +1,2 @@
flaskr.db flaskr.db
.eggs/

3
examples/flaskr/MANIFEST.in

@ -0,0 +1,3 @@
graft flaskr/templates
graft flaskr/static
include flaskr/schema.sql

18
examples/flaskr/README

@ -13,18 +13,26 @@
export an FLASKR_SETTINGS environment variable export an FLASKR_SETTINGS environment variable
pointing to a configuration file. pointing to a configuration file.
2. initialize the database with this command: 2. install the app from the root of the project directory
flask --app=flaskr initdb pip install --editable .
3. now you can run flaskr: 3. Instruct flask to use the right application
flask --app=flaskr run export FLASK_APP=flaskr
4. initialize the database with this command:
flask initdb
5. now you can run flaskr:
flask run
the application will greet you on the application will greet you on
http://localhost:5000/ http://localhost:5000/
~ Is it tested? ~ Is it tested?
You betcha. Run the `test_flaskr.py` file to see You betcha. Run `python setup.py test` to see
the tests pass. the tests pass.

1
examples/flaskr/flaskr/__init__.py

@ -0,0 +1 @@
from .flaskr import app

0
examples/flaskr/flaskr.py → examples/flaskr/flaskr/flaskr.py

0
examples/flaskr/schema.sql → examples/flaskr/flaskr/schema.sql

0
examples/flaskr/static/style.css → examples/flaskr/flaskr/static/style.css

0
examples/flaskr/templates/layout.html → examples/flaskr/flaskr/templates/layout.html

0
examples/flaskr/templates/login.html → examples/flaskr/flaskr/templates/login.html

4
examples/flaskr/templates/show_entries.html → examples/flaskr/flaskr/templates/show_entries.html

@ -13,9 +13,9 @@
{% endif %} {% endif %}
<ul class="entries"> <ul class="entries">
{% for entry in entries %} {% for entry in entries %}
<li><h2>{{ entry.title }}</h2>{{ entry.text|safe }} <li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}</li>
{% else %} {% else %}
<li><em>Unbelievable. No entries here so far</em> <li><em>Unbelievable. No entries here so far</em></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endblock %} {% endblock %}

2
examples/flaskr/setup.cfg

@ -0,0 +1,2 @@
[tool:pytest]
test=pytest

16
examples/flaskr/setup.py

@ -0,0 +1,16 @@
from setuptools import setup
setup(
name='flaskr',
packages=['flaskr'],
include_package_data=True,
install_requires=[
'flask',
],
setup_requires=[
'pytest-runner',
],
tests_require=[
'pytest',
],
)

5
examples/flaskr/test_flaskr.py → examples/flaskr/tests/test_flaskr.py

@ -9,11 +9,10 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import pytest
import os import os
import flaskr
import tempfile import tempfile
import pytest
from flaskr import flaskr
@pytest.fixture @pytest.fixture

2
examples/minitwit/.gitignore vendored

@ -0,0 +1,2 @@
minitwit.db
.eggs/

3
examples/minitwit/MANIFEST.in

@ -0,0 +1,3 @@
graft minitwit/templates
graft minitwit/static
include minitwit/schema.sql

18
examples/minitwit/README

@ -14,18 +14,26 @@
export an MINITWIT_SETTINGS environment variable export an MINITWIT_SETTINGS environment variable
pointing to a configuration file. pointing to a configuration file.
2. fire up a shell and run this: 2. install the app from the root of the project directory
flask --app=minitwit initdb pip install --editable .
3. now you can run minitwit: 3. tell flask about the right application:
flask --app=minitwit run export FLASK_APP=minitwit
4. fire up a shell and run this:
flask initdb
5. now you can run minitwit:
flask run
the application will greet you on the application will greet you on
http://localhost:5000/ http://localhost:5000/
~ Is it tested? ~ Is it tested?
You betcha. Run the `test_minitwit.py` file to You betcha. Run the `python setup.py test` file to
see the tests pass. see the tests pass.

1
examples/minitwit/minitwit/__init__.py

@ -0,0 +1 @@
from .minitwit import app

2
examples/minitwit/minitwit.py → examples/minitwit/minitwit/minitwit.py

@ -85,7 +85,7 @@ def format_datetime(timestamp):
def gravatar_url(email, size=80): def gravatar_url(email, size=80):
"""Return the gravatar image for the given email address.""" """Return the gravatar image for the given email address."""
return 'http://www.gravatar.com/avatar/%s?d=identicon&s=%d' % \ return 'https://www.gravatar.com/avatar/%s?d=identicon&s=%d' % \
(md5(email.strip().lower().encode('utf-8')).hexdigest(), size) (md5(email.strip().lower().encode('utf-8')).hexdigest(), size)

0
examples/minitwit/schema.sql → examples/minitwit/minitwit/schema.sql

0
examples/minitwit/static/style.css → examples/minitwit/minitwit/static/style.css

0
examples/minitwit/templates/layout.html → examples/minitwit/minitwit/templates/layout.html

0
examples/minitwit/templates/login.html → examples/minitwit/minitwit/templates/login.html

0
examples/minitwit/templates/register.html → examples/minitwit/minitwit/templates/register.html

0
examples/minitwit/templates/timeline.html → examples/minitwit/minitwit/templates/timeline.html

2
examples/minitwit/setup.cfg

@ -0,0 +1,2 @@
[aliases]
test=pytest

16
examples/minitwit/setup.py

@ -0,0 +1,16 @@
from setuptools import setup
setup(
name='minitwit',
packages=['minitwit'],
include_package_data=True,
install_requires=[
'flask',
],
setup_requires=[
'pytest-runner',
],
tests_require=[
'pytest',
],
)

2
examples/minitwit/test_minitwit.py → examples/minitwit/tests/test_minitwit.py

@ -9,9 +9,9 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import os import os
import minitwit
import tempfile import tempfile
import pytest import pytest
from minitwit import minitwit
@pytest.fixture @pytest.fixture

10
examples/patterns/largerapp/setup.py

@ -0,0 +1,10 @@
from setuptools import setup
setup(
name='yourapplication',
packages=['yourapplication'],
include_package_data=True,
install_requires=[
'flask',
],
)

12
examples/patterns/largerapp/tests/test_largerapp.py

@ -0,0 +1,12 @@
from yourapplication import app
import pytest
@pytest.fixture
def client():
app.config['TESTING'] = True
client = app.test_client()
return client
def test_index(client):
rv = client.get('/')
assert b"Hello World!" in rv.data

4
examples/patterns/largerapp/yourapplication/__init__.py

@ -0,0 +1,4 @@
from flask import Flask
app = Flask(__name__)
import yourapplication.views

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save