Browse Source

update project metadata

new readme
readme as setup.py long_description
links in changes
git in authors
add travis osx env
break out docs build in travis
remove python_requires for now
pull/2624/head
David Lord 7 years ago
parent
commit
9bf5c3b3a3
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
  1. 2
      .gitattributes
  2. 11
      .travis.yml
  3. 46
      AUTHORS
  4. 213
      CHANGES.rst
  5. 18
      CONTRIBUTING.rst
  6. 48
      LICENSE
  7. 2
      MANIFEST.in
  8. 18
      Makefile
  9. 49
      README
  10. 62
      README.rst
  11. 33
      docs/index.rst
  12. 309
      scripts/flaskext_tester.py
  13. 82
      scripts/make-release.py
  14. 2
      setup.cfg
  15. 65
      setup.py
  16. 3
      test-requirements.txt

2
.gitattributes vendored

@ -1 +1 @@
CHANGES merge=union CHANGES.rst merge=union

11
.travis.yml

@ -4,7 +4,9 @@ language: python
matrix: matrix:
include: include:
- python: 3.6 - python: 3.6
env: TOXENV=py,simplejson,devel,lowest,codecov,docs-html env: TOXENV=py,simplejson,devel,lowest,codecov
- python: 3.6
env: TOXENV=docs-html
- python: 3.5 - python: 3.5
env: TOXENV=py,codecov env: TOXENV=py,codecov
- python: 3.4 - python: 3.4
@ -15,9 +17,16 @@ matrix:
env: TOXENV=py,codecov env: TOXENV=py,codecov
- python: nightly - python: nightly
env: TOXENV=py env: TOXENV=py
- os: osx
language: generic
env: TOXENV=py
allow_failures: allow_failures:
- python: nightly - python: nightly
env: TOXENV=py env: TOXENV=py
- os: osx
language: generic
env: TOXENV=py
fast_finish: true
install: install:
- pip install tox - pip install tox

46
AUTHORS

@ -1,40 +1,12 @@
Flask is written and maintained by Armin Ronacher and Flask is developed and maintained by the Pallets team and community
various contributors: contributors. It was created by Armin Ronacher. The core maintainers
are:
Development Lead - David Lord (davidism)
```````````````` - Adrian Mönnich (ThiefMaster)
- Armin Ronacher (mitsuhiko)
- Marcus Unterwaditzer (untitaker)
- Armin Ronacher <armin.ronacher@active-4.com> A full list of contributors is available from git with::
Patches and Suggestions git shortlog -sne
```````````````````````
- Adam Byrtek
- Adam Zapletal
- Ali Afshar
- Chris Edgemon
- Chris Grindstaff
- Christopher Grebs
- Daniel Neuhäuser
- Dan Sully
- David Lord @davidism
- Edmond Burnett
- Florent Xicluna
- Georg Brandl
- Hsiaoming Yang @lepture
- Jeff Widman @jeffwidman
- Joshua Bronson @jab
- Justin Quick
- Kenneth Reitz
- Keyan Pishdadian
- Marian Sigler
- Martijn Pieters
- Matt Campell
- Matthew Frazier
- Michael van Tellingen
- Ron DuPlain
- Sebastien Estienne
- Simon Sapin
- Stephane Wirtel
- Thomas Schranz
- Zhao Xiaohong

213
CHANGES.rst

@ -1,3 +1,5 @@
.. currentmodule:: flask
Flask Changelog Flask Changelog
=============== ===============
@ -11,114 +13,126 @@ unreleased
- Bump minimum dependency versions to the latest stable versions: - Bump minimum dependency versions to the latest stable versions:
Werkzeug >= 0.14, Jinja >= 2.10, itsdangerous >= 0.24, Click >= 5.1. Werkzeug >= 0.14, Jinja >= 2.10, itsdangerous >= 0.24, Click >= 5.1.
(`#2586`_) (`#2586`_)
- Make ``app.run()`` into a noop if a Flask application is run from the - Skip :meth:`app.run <Flask.run>` when a Flask application is run from
development server on the command line. This avoids some behavior that the command line. This avoids some behavior that was confusing to
was confusing to debug for newcomers. debug.
- Change default configuration ``JSONIFY_PRETTYPRINT_REGULAR=False``. - Change the default for :data:`JSONIFY_PRETTYPRINT_REGULAR` to
``jsonify()`` method returns compressed response by default, and pretty ``False``. :func:`~json.jsonify` returns a compact format by default,
response in debug mode. (`#2193`_) and an indented format in debug mode. (`#2193`_)
- Change ``Flask.__init__`` to accept two new keyword arguments, - :meth:`Flask.__init__ <Flask>` accepts the ``host_matching`` argument
``host_matching`` and ``static_host``. This enables ``host_matching`` to be and sets it on :attr:`~Flask.url_map`. (`#1559`_)
set properly by the time the constructor adds the static route, and enables - :meth:`Flask.__init__ <Flask>` accepts the ``static_host`` argument
the static route to be properly associated with the required host. and passes it as the ``host`` argument when defining the static route.
(``#1559``) (`#1559`_)
- ``send_file`` supports Unicode in ``attachment_filename``. (`#2223`_) - :func:`send_file` supports Unicode in ``attachment_filename``.
- Pass ``_scheme`` argument from ``url_for`` to ``handle_build_error``. (`#2223`_)
(`#2017`_) - Pass ``_scheme`` argument from :func:`url_for` to
- Add support for ``provide_automatic_options`` in ``add_url_rule`` to disable :meth:`~Flask.handle_url_build_error`. (`#2017`_)
adding OPTIONS method when the ``view_func`` argument is not a class. - :meth:`~Flask.add_url_rule` accepts the ``provide_automatic_options``
(`#1489`_). argument to disable adding the ``OPTIONS`` method. (`#1489`_)
- ``MethodView`` can inherit method handlers from base classes. (`#1936`_) - :class:`~views.MethodView` subclasses inherit method handlers from
- Errors caused while opening the session at the beginning of the request are base classes. (`#1936`_)
handled by the app's error handlers. (`#2254`_) - Errors caused while opening the session at the beginning of the
- Blueprints gained ``json_encoder`` and ``json_decoder`` attributes to request are handled by the app's error handlers. (`#2254`_)
override the app's encoder and decoder. (`#1898`_) - Blueprints gained :attr:`~Blueprint.json_encoder` and
- ``Flask.make_response`` raises ``TypeError`` instead of ``ValueError`` for :attr:`~Blueprint.json_decoder` attributes to override the app's
bad response types. The error messages have been improved to describe why the encoder and decoder. (`#1898`_)
type is invalid. (`#2256`_) - :meth:`Flask.make_response` raises ``TypeError`` instead of
- Add ``routes`` CLI command to output routes registered on the application. ``ValueError`` for bad response types. The error messages have been
(`#2259`_) improved to describe why the type is invalid. (`#2256`_)
- Add ``routes`` CLI command to output routes registered on the
application. (`#2259`_)
- Show warning when session cookie domain is a bare hostname or an IP - Show warning when session cookie domain is a bare hostname or an IP
address, as these may not behave properly in some browsers, such as Chrome. address, as these may not behave properly in some browsers, such as
(`#2282`_) Chrome. (`#2282`_)
- Allow IP address as exact session cookie domain. (`#2282`_) - Allow IP address as exact session cookie domain. (`#2282`_)
- ``SESSION_COOKIE_DOMAIN`` is set if it is detected through ``SERVER_NAME``. - ``SESSION_COOKIE_DOMAIN`` is set if it is detected through
(`#2282`_) ``SERVER_NAME``. (`#2282`_)
- Auto-detect zero-argument app factory called ``create_app`` or ``make_app`` - Auto-detect zero-argument app factory called ``create_app`` or
from ``FLASK_APP``. (`#2297`_) ``make_app`` from ``FLASK_APP``. (`#2297`_)
- Factory functions are not required to take a ``script_info`` parameter to - Factory functions are not required to take a ``script_info`` parameter
work with the ``flask`` command. If they take a single parameter or a to work with the ``flask`` command. If they take a single parameter or
parameter named ``script_info``, the ``ScriptInfo`` object will be passed. a parameter named ``script_info``, the :class:`~cli.ScriptInfo` object
(`#2319`_) will be passed. (`#2319`_)
- FLASK_APP=myproject.app:create_app('dev') support. - ``FLASK_APP`` can be set to an app factory, with arguments if needed,
- ``FLASK_APP`` can be set to an app factory, with arguments if needed, for for example ``FLASK_APP=myproject.app:create_app('dev')``. (`#2326`_)
example ``FLASK_APP=myproject.app:create_app('dev')``. (`#2326`_) - ``FLASK_APP`` can point to local packages that are not installed in
- ``FLASK_APP`` can point to local packages that are not installed in dev mode, editable mode, although ``pip install -e`` is still preferred.
although `pip install -e` should still be preferred. (`#2414`_) (`#2414`_)
- ``View.provide_automatic_options = True`` is set on the view function from - The :class:`~views.View` class attribute
``View.as_view``, to be detected in ``app.add_url_rule``. (`#2316`_) :attr:`~views.View.provide_automatic_options` is set in
:meth:`~views.View.as_view`, to be detected by
:meth:`~Flask.add_url_rule`. (`#2316`_)
- Error handling will try handlers registered for ``blueprint, code``, - Error handling will try handlers registered for ``blueprint, code``,
``app, code``, ``blueprint, exception``, ``app, exception``. (`#2314`_) ``app, code``, ``blueprint, exception``, ``app, exception``.
- ``Cookie`` is added to the response's ``Vary`` header if the session is (`#2314`_)
accessed at all during the request (and it wasn't deleted). (`#2288`_) - ``Cookie`` is added to the response's ``Vary`` header if the session
- ``app.test_request_context()`` take ``subdomain`` and ``url_scheme`` is accessed at all during the request (and not deleted). (`#2288`_)
parameters for use when building base URL. (`#1621`_) - :meth:`~Flask.test_request_context` accepts ``subdomain`` and
- Set ``APPLICATION_ROOT = '/'`` by default. This was already the implicit ``url_scheme`` arguments for use when building the base URL.
default when it was set to ``None``. (`#1621`_)
- ``TRAP_BAD_REQUEST_ERRORS`` is enabled by default in debug mode. - Set :data:`APPLICATION_ROOT` to ``'/'`` by default. This was already
``BadRequestKeyError`` has a message with the bad key in debug mode instead the implicit default when it was set to ``None``.
of the generic bad request message. (`#2348`_) - :data:`TRAP_BAD_REQUEST_ERRORS` is enabled by default in debug mode.
- Allow registering new tags with ``TaggedJSONSerializer`` to support ``BadRequestKeyError`` has a message with the bad key in debug mode
storing other types in the session cookie. (`#2352`_) instead of the generic bad request message. (`#2348`_)
- Only open the session if the request has not been pushed onto the context - Allow registering new tags with
stack yet. This allows ``stream_with_context`` generators to access the same :class:`~json.tag.TaggedJSONSerializer` to support storing other types
session that the containing view uses. (`#2354`_) in the session cookie. (`#2352`_)
- Add ``json`` keyword argument for the test client request methods. This will - Only open the session if the request has not been pushed onto the
dump the given object as JSON and set the appropriate content type. context stack yet. This allows :func:`~stream_with_context`
(`#2358`_) generators to access the same session that the containing view uses.
- Extract JSON handling to a mixin applied to both the request and response (`#2354`_)
classes used by Flask. This adds the ``is_json`` and ``get_json`` methods to - Add ``json`` keyword argument for the test client request methods.
the response to make testing JSON response much easier. (`#2358`_) This will dump the given object as JSON and set the appropriate
- Removed error handler caching because it caused unexpected results for some content type. (`#2358`_)
exception inheritance hierarchies. Register handlers explicitly for each - Extract JSON handling to a mixin applied to both the :class:`Request`
exception if you don't want to traverse the MRO. (`#2362`_) and :class:`Response` classes. This adds the :meth:`~Response.is_json`
and :meth:`~Response.get_json` methods to the response to make testing
JSON response much easier. (`#2358`_)
- Removed error handler caching because it caused unexpected results for
some exception inheritance hierarchies. Register handlers explicitly
for each exception if you want to avoid traversing the MRO. (`#2362`_)
- Fix incorrect JSON encoding of aware, non-UTC datetimes. (`#2374`_) - Fix incorrect JSON encoding of aware, non-UTC datetimes. (`#2374`_)
- Template auto reloading will honor the ``run`` command's ``debug`` flag even - Template auto reloading will honor debug mode even even if
if ``app.jinja_env`` was already accessed. (`#2373`_) :attr:`~Flask.jinja_env` was already accessed. (`#2373`_)
- The following old deprecated code was removed. (`#2385`_) - The following old deprecated code was removed. (`#2385`_)
- ``flask.ext`` - import extensions directly by their name instead of - ``flask.ext`` - import extensions directly by their name instead of
through the ``flask.ext`` namespace. For example, through the ``flask.ext`` namespace. For example,
``import flask.ext.sqlalchemy`` becomes ``import flask_sqlalchemy``. ``import flask.ext.sqlalchemy`` becomes ``import flask_sqlalchemy``.
- ``Flask.init_jinja_globals`` - extend ``Flask.create_jinja_environment`` - ``Flask.init_jinja_globals`` - extend
instead. :meth:`Flask.create_jinja_environment` instead.
- ``Flask.error_handlers`` - tracked by ``Flask.error_handler_spec``, - ``Flask.error_handlers`` - tracked by
use ``@app.errorhandler`` to register handlers. :attr:`Flask.error_handler_spec`, use :meth:`Flask.errorhandler` to
- ``Flask.request_globals_class`` - use ``Flask.app_ctx_globals_class`` register handlers.
instead. - ``Flask.request_globals_class`` - use
- ``Flask.static_path`` - use ``Flask.static_url_path`` instead. :attr:`Flask.app_ctx_globals_class` instead.
- ``Request.module`` - use ``Request.blueprint`` instead. - ``Flask.static_path`` - use :attr:`Flask.static_url_path` instead.
- ``Request.module`` - use :attr:`Request.blueprint` instead.
- The ``request.json`` property is no longer deprecated. (`#1421`_)
- Support passing an existing ``EnvironBuilder`` or ``dict`` to - The :attr:`Request.json` property is no longer deprecated. (`#1421`_)
``test_client.open``. (`#2412`_) - Support passing a :class:`~werkzeug.test.EnvironBuilder` or
- The ``flask`` command and ``app.run`` will load environment variables using ``dict`` to :meth:`test_client.open <werkzeug.test.Client.open>`.
from ``.env`` and ``.flaskenv`` files if python-dotenv is installed. (`#2412`_)
(`#2416`_) - The ``flask`` command and :meth:`Flask.run` will load environment
- When passing a full URL to the test client, use the scheme in the URL instead variables from ``.env`` and ``.flaskenv`` files if python-dotenv is
of the ``PREFERRED_URL_SCHEME``. (`#2430`_) installed. (`#2416`_)
- ``app.logger`` has been simplified. ``LOGGER_NAME`` and - When passing a full URL to the test client, the scheme in the URL is
``LOGGER_HANDLER_POLICY`` config was removed. The logger is always named used instead of :data:`PREFERRED_URL_SCHEME`. (`#2430`_)
``flask.app``. The level is only set on first access, it doesn't check - :attr:`Flask.logger` has been simplified. ``LOGGER_NAME`` and
``app.debug`` each time. Only one format is used, not different ones ``LOGGER_HANDLER_POLICY`` config was removed. The logger is always
depending on ``app.debug``. No handlers are removed, and a handler is only named ``flask.app``. The level is only set on first access, it doesn't
added if no handlers are already configured. (`#2436`_) check :attr:`Flask.debug` each time. Only one format is used, not
- Blueprint view function name may not contain dots. (`#2450`_) different ones depending on :attr:`Flask.debug`. No handlers are
- Fix a ``ValueError`` caused by invalid Range requests in some cases. removed, and a handler is only added if no handlers are already
(`#2526`_) configured. (`#2436`_)
- The dev server now uses threads by default. (`#2529`_) - Blueprint view function names may not contain dots. (`#2450`_)
- Loading config files with ``silent=True`` will ignore ``ENOTDIR`` - Fix a ``ValueError`` caused by invalid ``Range`` requests in some
errors. (`#2581`_) cases. (`#2526`_)
- The development server uses threads by default. (`#2529`_)
- Loading config files with ``silent=True`` will ignore
:data:`~errno.ENOTDIR` errors. (`#2581`_)
- Pass ``--cert`` and ``--key`` options to ``flask run`` to run the - Pass ``--cert`` and ``--key`` options to ``flask run`` to run the
development server over HTTPS. (`#2606`_) development server over HTTPS. (`#2606`_)
- Added :data:`SESSION_COOKIE_SAMESITE` to control the ``SameSite`` - Added :data:`SESSION_COOKIE_SAMESITE` to control the ``SameSite``
@ -127,6 +141,7 @@ unreleased
.. _pallets/meta#24: https://github.com/pallets/meta/issues/24 .. _pallets/meta#24: https://github.com/pallets/meta/issues/24
.. _#1421: https://github.com/pallets/flask/issues/1421 .. _#1421: https://github.com/pallets/flask/issues/1421
.. _#1489: https://github.com/pallets/flask/pull/1489 .. _#1489: https://github.com/pallets/flask/pull/1489
.. _#1559: https://github.com/pallets/flask/issues/1559
.. _#1621: https://github.com/pallets/flask/pull/1621 .. _#1621: https://github.com/pallets/flask/pull/1621
.. _#1898: https://github.com/pallets/flask/pull/1898 .. _#1898: https://github.com/pallets/flask/pull/1898
.. _#1936: https://github.com/pallets/flask/pull/1936 .. _#1936: https://github.com/pallets/flask/pull/1936

18
CONTRIBUTING.rst

@ -131,8 +131,22 @@ Read more about `coverage <https://coverage.readthedocs.io>`_.
Running the full test suite with ``tox`` will combine the coverage reports Running the full test suite with ``tox`` will combine the coverage reports
from all runs. from all runs.
``make`` targets
~~~~~~~~~~~~~~~~ Building the docs
~~~~~~~~~~~~~~~~~
Build the docs in the ``docs`` directory using Sphinx::
cd docs
make html
Open ``_build/html/index.html`` in your browser to view the docs.
Read more about `Sphinx <http://www.sphinx-doc.org>`_.
make targets
~~~~~~~~~~~~
Flask provides a ``Makefile`` with various shortcuts. They will ensure that Flask provides a ``Makefile`` with various shortcuts. They will ensure that
all dependencies are installed. all dependencies are installed.

48
LICENSE

@ -1,33 +1,31 @@
Copyright (c) 2015 by Armin Ronacher and contributors. See AUTHORS Copyright © 2010 by the Pallets team.
for more details.
Some rights reserved. Some rights reserved.
Redistribution and use in source and binary forms of the software as well Redistribution and use in source and binary forms of the software as
as documentation, with or without modification, are permitted provided well as documentation, with or without modification, are permitted
that the following conditions are met: provided that the following conditions are met:
* Redistributions of source code must retain the above copyright * Redistributions of source code must retain the above copyright notice,
notice, this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above * Redistributions in binary form must reproduce the above copyright
copyright notice, this list of conditions and the following notice, this list of conditions and the following disclaimer in the
disclaimer in the documentation and/or other materials provided documentation and/or other materials provided with the distribution.
with the distribution.
* The names of the contributors may not be used to endorse or * Neither the name of the copyright holder nor the names of its
promote products derived from this software without specific contributors may be used to endorse or promote products derived from
prior written permission. this software without specific prior written permission.
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
DAMAGE. SUCH DAMAGE.

2
MANIFEST.in

@ -1,4 +1,4 @@
include Makefile CHANGES LICENSE AUTHORS tox.ini include Makefile CHANGES.rst LICENSE AUTHORS tox.ini
graft artwork graft artwork
graft tests graft tests

18
Makefile

@ -9,7 +9,6 @@ test: clean-pyc install-dev
pytest pytest
coverage: clean-pyc install-dev coverage: clean-pyc install-dev
pip install -q -e .[test]
coverage run -m pytest coverage run -m pytest
coverage report coverage report
coverage html coverage html
@ -34,20 +33,3 @@ clean-pyc:
find . -name '*.pyc' -exec rm -f {} + find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} + find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} + find . -name '*~' -exec rm -f {} +
upload-docs:
$(MAKE) -C docs html dirhtml latex epub
$(MAKE) -C docs/_build/latex all-pdf
cd docs/_build/; mv html flask-docs; zip -r flask-docs.zip flask-docs; mv flask-docs html
rsync -a docs/_build/dirhtml/ flow.srv.pocoo.org:/srv/websites/flask.pocoo.org/docs/
rsync -a docs/_build/latex/Flask.pdf flow.srv.pocoo.org:/srv/websites/flask.pocoo.org/docs/flask-docs.pdf
rsync -a docs/_build/flask-docs.zip flow.srv.pocoo.org:/srv/websites/flask.pocoo.org/docs/flask-docs.zip
rsync -a docs/_build/epub/Flask.epub flow.srv.pocoo.org:/srv/websites/flask.pocoo.org/docs/flask-docs.epub
# ebook-convert docs: http://manual.calibre-ebook.com/cli/ebook-convert.html
ebook:
@echo 'Using .epub from `make upload-docs` to create .mobi.'
@echo 'Command `ebook-covert` is provided by calibre package.'
@echo 'Requires X-forwarding for Qt features used in conversion (ssh -X).'
@echo 'Do not mind "Invalid value for ..." CSS errors if .mobi renders.'
ssh -X pocoo.org ebook-convert /var/www/flask.pocoo.org/docs/flask-docs.epub /var/www/flask.pocoo.org/docs/flask-docs.mobi --cover http://flask.pocoo.org/docs/_images/logo-full.png --authors 'Armin Ronacher'

49
README

@ -1,49 +0,0 @@
// Flask //
web development, one drop at a time
~ What is Flask?
Flask is a microframework for Python based on Werkzeug
and Jinja2. It's intended for getting started very quickly
and was developed with best intentions in mind.
~ Is it ready?
It's still not 1.0 but it's shaping up nicely and is
already widely used. Consider the API to slightly
improve over time but we don't plan on breaking it.
~ What do I need?
All dependencies are installed by using `pip install Flask`.
We encourage you to use a virtualenv. Check the docs for
complete installation and usage instructions.
~ Where are the docs?
Go to http://flask.pocoo.org/docs/ for a prebuilt version
of the current documentation. Otherwise build them yourself
from the sphinx sources in the docs folder.
~ Where are the tests?
Good that you're asking. The tests are in the
tests/ folder. To run the tests use the
`pytest` testing tool:
$ pytest
Details on contributing can be found in CONTRIBUTING.rst
~ Where can I get help?
Either use the #pocoo IRC channel on irc.freenode.net or
ask on the mailinglist: http://flask.pocoo.org/mailinglist/
See http://flask.pocoo.org/community/ for more resources.

62
README.rst

@ -0,0 +1,62 @@
Flask
=====
Flask is a lightweight `WSGI`_ web application framework. It is designed
to make getting started quick and easy, with the ability to scale up to
complex applications. It began as a simple wrapper around `Werkzeug`_
and `Jinja`_ and has become one of the most popular Python web
application frameworks.
Flask offers suggestions, but doesn't enforce any dependencies or
project layout. It is up to the developer to choose the tools and
libraries they want to use. There are many extensions provided by the
community that make adding new functionality easy.
Installing
----------
Install and update using `pip`_:
.. code-block:: text
pip install -U Flask
A Simple Example
----------------
.. code-block:: python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
.. code-block:: none
$ FLASK_APP=hello.py flask run
* Running on http://localhost:5000/
Links
-----
* Website: https://www.palletsprojects.com/p/flask/
* Releases: https://pypi.org/project/Flask/
* Code: https://github.com/pallets/flask
* Issue tracker: https://github.com/pallets/flask/issues
* Test status:
* Linux, Mac: https://travis-ci.org/pallets/flask
* Windows: https://ci.appveyor.com/project/pallets/flask
* Test coverage: https://codecov.io/gh/pallets/flask
.. _WSGI: https://wsgi.readthedocs.io
.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/
.. _Jinja: https://www.palletsprojects.com/p/jinja/
.. _pip: https://pip.pypa.io/en/stable/quickstart/

33
docs/index.rst

@ -4,28 +4,23 @@ Welcome to Flask
================ ================
.. image:: _static/logo-full.png .. image:: _static/logo-full.png
:alt: Flask: web development, one drop at a time :alt: Flask: web development, one drop at a time
:class: floatingflask :class: floatingflask
Welcome to Flask's documentation. This documentation is divided into Welcome to Flask's documentation. Get started with :ref:`installation`
different parts. I recommend that you get started with and then get an overview with the :ref:`quickstart`. There is also a
:ref:`installation` and then head over to the :ref:`quickstart`. more detailed :ref:`tutorial` that shows how to create a small but
Besides the quickstart, there is also a more detailed :ref:`tutorial` that complete application with Flask. Common patterns are described in the
shows how to create a complete (albeit small) application with Flask. If :ref:`patterns` section. The rest of the docs desribe each component of
you'd rather dive into the internals of Flask, check out Flask in detail, with a full reference in the :ref:`api` section.
the :ref:`api` documentation. Common patterns are described in the
:ref:`patterns` section.
Flask depends on two external libraries: the `Jinja2`_ template Flask depends on the `Jinja`_ template engine and the `Werkzeug`_ WSGI
engine and the `Werkzeug`_ WSGI toolkit. These libraries are not documented toolkit. The documentation for these libraries can be found at:
here. If you want to dive into their documentation, check out the
following links:
- `Jinja2 Documentation <http://jinja.pocoo.org/docs>`_ - `Jinja documentation <http://jinja.pocoo.org/docs>`_
- `Werkzeug Documentation <http://werkzeug.pocoo.org/docs>`_ - `Werkzeug documentation <http://werkzeug.pocoo.org/docs>`_
.. _Jinja: https://www.palletsprojects.com/p/jinja/
.. _Jinja2: http://jinja.pocoo.org/ .. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/
.. _Werkzeug: http://werkzeug.pocoo.org/
.. include:: contents.rst.inc .. include:: contents.rst.inc

309
scripts/flaskext_tester.py

@ -1,309 +0,0 @@
# -*- coding: utf-8 -*-
"""
Flask Extension Tests
~~~~~~~~~~~~~~~~~~~~~
Tests the Flask extensions.
:copyright: (c) 2015 by Ali Afshar.
:license: BSD, see LICENSE for more details.
"""
import os
import sys
import shutil
import urllib2
import tempfile
import subprocess
import argparse
from flask import json
from setuptools.package_index import PackageIndex
from setuptools.archive_util import unpack_archive
flask_svc_url = 'http://flask.pocoo.org/extensions/'
# OS X has awful paths when using mkstemp or gettempdir(). I don't
# care about security or clashes here, so pick something that is
# actually memorable.
if sys.platform == 'darwin':
_tempdir = '/private/tmp'
else:
_tempdir = tempfile.gettempdir()
tdir = _tempdir + '/flaskext-test'
flaskdir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
# virtualenv hack *cough*
os.environ['PYTHONDONTWRITEBYTECODE'] = ''
RESULT_TEMPATE = u'''\
<!doctype html>
<title>Flask-Extension Test Results</title>
<style type=text/css>
body { font-family: 'Georgia', serif; font-size: 17px; color: #000; }
a { color: #004B6B; }
a:hover { color: #6D4100; }
h1, h2, h3 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; }
h1 { font-size: 30px; margin: 15px 0 5px 0; }
h2 { font-size: 24px; margin: 15px 0 5px 0; }
h3 { font-size: 19px; margin: 15px 0 5px 0; }
textarea, code,
pre { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace!important; font-size: 15px;
background: #eee; }
pre { padding: 7px 15px; line-height: 1.3; }
p { line-height: 1.4; }
table { border: 1px solid black; border-collapse: collapse;
margin: 15px 0; }
td, th { border: 1px solid black; padding: 4px 10px;
text-align: left; }
th { background: #eee; font-weight: normal; }
tr.success { background: #D3F5CC; }
tr.failed { background: #F5D2CB; }
</style>
<h1>Flask-Extension Test Results</h1>
<p>
This page contains the detailed test results for the test run of
all {{ 'approved' if approved }} Flask extensions.
<h2>Summary</h2>
<table class=results>
<thead>
<tr>
<th>Extension
<th>Version
<th>Author
<th>License
<th>Outcome
{%- for iptr, _ in results[0].logs|dictsort %}
<th>{{ iptr }}
{%- endfor %}
</tr>
</thead>
<tbody>
{%- for result in results %}
{% set outcome = 'success' if result.success else 'failed' %}
<tr class={{ outcome }}>
<th>{{ result.name }}
<td>{{ result.version }}
<td>{{ result.author }}
<td>{{ result.license }}
<td>{{ outcome }}
{%- for iptr, _ in result.logs|dictsort %}
<td><a href="#{{ result.name }}-{{ iptr }}">see log</a>
{%- endfor %}
</tr>
{%- endfor %}
</tbody>
</table>
<h2>Test Logs</h2>
<p>Detailed test logs for all tests on all platforms:
{%- for result in results %}
{%- for iptr, log in result.logs|dictsort %}
<h3 id="{{ result.name }}-{{ iptr }}">
{{ result.name }} - {{ result.version }} [{{ iptr }}]</h3>
<pre>{{ log }}</pre>
{%- endfor %}
{%- endfor %}
'''
def log(msg, *args):
print('[EXTTEST] ' + (msg % args))
class TestResult(object):
def __init__(self, name, folder, statuscode, interpreters):
intrptr = os.path.join(folder, '.tox/%s/bin/python'
% interpreters[0])
self.statuscode = statuscode
self.folder = folder
self.success = statuscode == 0
def fetch(field):
try:
c = subprocess.Popen([intrptr, 'setup.py',
'--' + field], cwd=folder,
stdout=subprocess.PIPE)
return c.communicate()[0].strip()
except OSError:
return '?'
self.name = name
self.license = fetch('license')
self.author = fetch('author')
self.version = fetch('version')
self.logs = {}
for interpreter in interpreters:
logfile = os.path.join(folder, '.tox/%s/log/test.log'
% interpreter)
if os.path.isfile(logfile):
self.logs[interpreter] = open(logfile).read()
else:
self.logs[interpreter] = ''
def create_tdir():
try:
shutil.rmtree(tdir)
except Exception:
pass
os.mkdir(tdir)
def package_flask():
distfolder = tdir + '/.flask-dist'
c = subprocess.Popen(['python', 'setup.py', 'sdist', '--formats=gztar',
'--dist', distfolder], cwd=flaskdir)
c.wait()
return os.path.join(distfolder, os.listdir(distfolder)[0])
def get_test_command(checkout_dir):
if os.path.isfile(checkout_dir + '/Makefile'):
return 'make test'
return 'python setup.py test'
def fetch_extensions_list():
req = urllib2.Request(flask_svc_url, headers={'accept':'application/json'})
d = urllib2.urlopen(req).read()
data = json.loads(d)
for ext in data['extensions']:
yield ext
def checkout_extension(name):
log('Downloading extension %s to temporary folder', name)
root = os.path.join(tdir, name)
os.mkdir(root)
checkout_path = PackageIndex().download(name, root)
unpack_archive(checkout_path, root)
path = None
for fn in os.listdir(root):
path = os.path.join(root, fn)
if os.path.isdir(path):
break
log('Downloaded to %s', path)
return path
tox_template = """[tox]
envlist=%(env)s
[testenv]
deps=
%(deps)s
distribute
py
commands=bash flaskext-runtest.sh {envlogdir}/test.log
downloadcache=%(cache)s
"""
def create_tox_ini(checkout_path, interpreters, flask_dep):
tox_path = os.path.join(checkout_path, 'tox-flask-test.ini')
if not os.path.exists(tox_path):
with open(tox_path, 'w') as f:
f.write(tox_template % {
'env': ','.join(interpreters),
'cache': tdir,
'deps': flask_dep
})
return tox_path
def iter_extensions(only_approved=True):
for ext in fetch_extensions_list():
if ext['approved'] or not only_approved:
yield ext['name']
def test_extension(name, interpreters, flask_dep):
checkout_path = checkout_extension(name)
log('Running tests with tox in %s', checkout_path)
# figure out the test command and write a wrapper script. We
# can't write that directly into the tox ini because tox does
# not invoke the command from the shell so we have no chance
# to pipe the output into a logfile. The /dev/null hack is
# to trick py.test (if used) into not guessing widths from the
# invoking terminal.
test_command = get_test_command(checkout_path)
log('Test command: %s', test_command)
f = open(checkout_path + '/flaskext-runtest.sh', 'w')
f.write(test_command + ' &> "$1" < /dev/null\n')
f.close()
# if there is a tox.ini, remove it, it will cause troubles
# for us. Remove it if present, we are running tox ourselves
# afterall.
create_tox_ini(checkout_path, interpreters, flask_dep)
rv = subprocess.call(['tox', '-c', 'tox-flask-test.ini'], cwd=checkout_path)
return TestResult(name, checkout_path, rv, interpreters)
def run_tests(extensions, interpreters):
results = {}
create_tdir()
log('Packaging Flask')
flask_dep = package_flask()
log('Running extension tests')
log('Temporary Environment: %s', tdir)
for name in extensions:
log('Testing %s', name)
result = test_extension(name, interpreters, flask_dep)
if result.success:
log('Extension test succeeded')
else:
log('Extension test failed')
results[name] = result
return results
def render_results(results, approved):
from jinja2 import Template
items = results.values()
items.sort(key=lambda x: x.name.lower())
rv = Template(RESULT_TEMPATE, autoescape=True).render(results=items,
approved=approved)
fd, filename = tempfile.mkstemp(suffix='.html')
os.fdopen(fd, 'w').write(rv.encode('utf-8') + '\n')
return filename
def main():
parser = argparse.ArgumentParser(description='Runs Flask extension tests')
parser.add_argument('--all', dest='all', action='store_true',
help='run against all extensions, not just approved')
parser.add_argument('--browse', dest='browse', action='store_true',
help='show browser with the result summary')
parser.add_argument('--env', dest='env', default='py25,py26,py27',
help='the tox environments to run against')
parser.add_argument('--extension=', dest='extension', default=None,
help='tests a single extension')
args = parser.parse_args()
if args.extension is not None:
only_approved = False
extensions = [args.extension]
else:
only_approved = not args.all
extensions = iter_extensions(only_approved)
results = run_tests(extensions, [x.strip() for x in args.env.split(',')])
filename = render_results(results, only_approved)
if args.browse:
import webbrowser
webbrowser.open('file:///' + filename.lstrip('/'))
print('Results written to {}'.format(filename))
if __name__ == '__main__':
main()

82
scripts/make-release.py

@ -1,23 +1,13 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
make-release
~~~~~~~~~~~~
Helper script that performs a release. Does pretty much everything
automatically for us.
:copyright: (c) 2015 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from __future__ import print_function from __future__ import print_function
import sys
import os import os
import re import re
from datetime import datetime, date import sys
from subprocess import Popen, PIPE from datetime import date, datetime
from subprocess import PIPE, Popen
_date_clean_re = re.compile(r'(\d+)(st|nd|rd|th)') _date_strip_re = re.compile(r'(?<=\d)(st|nd|rd|th)')
def parse_changelog(): def parse_changelog():
@ -25,18 +15,27 @@ def parse_changelog():
lineiter = iter(f) lineiter = iter(f)
for line in lineiter: for line in lineiter:
match = re.search('^Version\s+(.*)', line.strip()) match = re.search('^Version\s+(.*)', line.strip())
if match is None: if match is None:
continue continue
version = match.group(1).strip() version = match.group(1).strip()
if lineiter.next().count('-') != len(match.group(0)):
if next(lineiter).count('-') != len(match.group(0)):
continue continue
while 1: while 1:
change_info = lineiter.next().strip() change_info = next(lineiter).strip()
if change_info: if change_info:
break break
match = re.search(r'released on (\w+\s+\d+\w+\s+\d+)' match = re.search(
r'(?:, codename (.*))?(?i)', change_info) r'released on (\w+\s+\d+\w+\s+\d+)(?:, codename (.*))?',
change_info,
flags=re.IGNORECASE
)
if match is None: if match is None:
continue continue
@ -46,15 +45,16 @@ def parse_changelog():
def bump_version(version): def bump_version(version):
try: try:
parts = map(int, version.split('.')) parts = [int(i) for i in version.split('.')]
except ValueError: except ValueError:
fail('Current version is not numeric') fail('Current version is not numeric')
parts[-1] += 1 parts[-1] += 1
return '.'.join(map(str, parts)) return '.'.join(map(str, parts))
def parse_date(string): def parse_date(string):
string = _date_clean_re.sub(r'\1', string) string = _date_strip_re.sub('', string)
return datetime.strptime(string, '%B %d %Y') return datetime.strptime(string, '%B %d %Y')
@ -65,9 +65,13 @@ def set_filename_version(filename, version_number, pattern):
before, old, after = match.groups() before, old, after = match.groups()
changed.append(True) changed.append(True)
return before + version_number + after return before + version_number + after
with open(filename) as f: with open(filename) as f:
contents = re.sub(r"^(\s*%s\s*=\s*')(.+?)(')(?sm)" % pattern, contents = re.sub(
inject_version, f.read()) r"^(\s*%s\s*=\s*')(.+?)(')" % pattern,
inject_version, f.read(),
flags=re.DOTALL | re.MULTILINE
)
if not changed: if not changed:
fail('Could not find %s in %s', pattern, filename) fail('Could not find %s in %s', pattern, filename)
@ -81,8 +85,9 @@ def set_init_version(version):
set_filename_version('flask/__init__.py', version, '__version__') set_filename_version('flask/__init__.py', version, '__version__')
def build_and_upload(): def build():
Popen([sys.executable, 'setup.py', 'release', 'sdist', 'bdist_wheel', 'upload']).wait() cmd = [sys.executable, 'setup.py', 'sdist', 'bdist_wheel']
Popen(cmd).wait()
def fail(message, *args): def fail(message, *args):
@ -95,7 +100,9 @@ def info(message, *args):
def get_git_tags(): def get_git_tags():
return set(Popen(['git', 'tag'], stdout=PIPE).communicate()[0].splitlines()) return set(
Popen(['git', 'tag'], stdout=PIPE).communicate()[0].splitlines()
)
def git_is_clean(): def git_is_clean():
@ -116,29 +123,40 @@ def main():
os.chdir(os.path.join(os.path.dirname(__file__), '..')) os.chdir(os.path.join(os.path.dirname(__file__), '..'))
rv = parse_changelog() rv = parse_changelog()
if rv is None: if rv is None:
fail('Could not parse changelog') fail('Could not parse changelog')
version, release_date, codename = rv version, release_date, codename = rv
dev_version = bump_version(version) + '-dev' dev_version = bump_version(version) + '.dev'
info('Releasing %s (codename %s, release date %s)', info(
version, codename, release_date.strftime('%d/%m/%Y')) 'Releasing %s (codename %s, release date %s)',
version, codename, release_date.strftime('%d/%m/%Y')
)
tags = get_git_tags() tags = get_git_tags()
if version in tags: if version in tags:
fail('Version "%s" is already tagged', version) fail('Version "%s" is already tagged', version)
if release_date.date() != date.today(): if release_date.date() != date.today():
fail('Release date is not today (%s != %s)', fail(
release_date.date(), date.today()) 'Release date is not today (%s != %s)',
release_date.date(), date.today()
)
if not git_is_clean(): if not git_is_clean():
fail('You have uncommitted changes in git') fail('You have uncommitted changes in git')
try:
import wheel # noqa: F401
except ImportError:
fail('You need to install the wheel package.')
set_init_version(version) set_init_version(version)
make_git_commit('Bump version number to %s', version) make_git_commit('Bump version number to %s', version)
make_git_tag(version) make_git_tag(version)
build_and_upload() build()
set_init_version(dev_version) set_init_version(dev_version)

2
setup.cfg

@ -1,5 +1,5 @@
[aliases] [aliases]
release = egg_info -RDb '' release = egg_info -Db ''
[bdist_wheel] [bdist_wheel]
universal = 1 universal = 1

65
setup.py

@ -1,74 +1,27 @@
""" #!/usr/bin/env python
Flask import io
-----
Flask is a microframework for Python based on Werkzeug, Jinja 2 and good
intentions. And before you ask: It's BSD licensed!
Flask is Fun
````````````
Save in a hello.py:
.. code:: python
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
And Easy to Setup
`````````````````
And run it:
.. code:: bash
$ pip install Flask
$ python hello.py
* Running on http://localhost:5000/
Ready for production? `Read this first <http://flask.pocoo.org/docs/deploying/>`.
Links
`````
* `website <http://flask.pocoo.org/>`_
* `documentation <http://flask.pocoo.org/docs/>`_
* `development version
<https://github.com/pallets/flask/zipball/master#egg=Flask-dev>`_
"""
import re import re
import ast
from setuptools import setup from setuptools import setup
_version_re = re.compile(r'__version__\s+=\s+(.*)') with io.open('README.rst', 'rt', encoding='utf8') as f:
readme = f.read()
with open('flask/__init__.py', 'rb') as f: with io.open('flask/__init__.py', 'rt', encoding='utf8') as f:
version = str(ast.literal_eval(_version_re.search( version = re.search(r'__version__ = \'(.*?)\'', f.read()).group(1)
f.read().decode('utf-8')).group(1)))
setup( setup(
name='Flask', name='Flask',
version=version, version=version,
url='https://github.com/pallets/flask/', url='https://www.palletsprojects.com/p/flask/',
license='BSD', license='BSD',
author='Armin Ronacher', author='Armin Ronacher',
author_email='armin.ronacher@active-4.com', author_email='armin.ronacher@active-4.com',
description='A microframework based on Werkzeug, Jinja2 ' description='A simple framework for building complex web applications.',
'and good intentions', long_description=readme,
long_description=__doc__,
packages=['flask', 'flask.json'], packages=['flask', 'flask.json'],
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,
platforms='any', platforms='any',
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
install_requires=[ install_requires=[
'Werkzeug>=0.14', 'Werkzeug>=0.14',
'Jinja2>=2.10', 'Jinja2>=2.10',

3
test-requirements.txt

@ -1,3 +0,0 @@
tox
pytest
pytest-cov
Loading…
Cancel
Save