Browse Source

Merge pull request #1 from pallets/master

added new
pull/2770/head
babygame0ver 7 years ago committed by GitHub
parent
commit
0e342302b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 81
      CHANGES.rst
  2. 12
      README.rst
  3. 13
      docs/api.rst
  4. 2
      docs/blueprints.rst
  5. 24
      docs/cli.rst
  6. 2
      docs/conf.py
  7. 2
      docs/config.rst
  8. 8
      docs/flaskstyle.sty
  9. 2
      docs/patterns/fileuploads.rst
  10. 6
      docs/quickstart.rst
  11. 2
      docs/tutorial/static.rst
  12. 2
      docs/upgrading.rst
  13. 2
      flask/__init__.py
  14. 22
      flask/app.py
  15. 15
      flask/blueprints.py
  16. 11
      flask/cli.py
  17. 15
      flask/helpers.py
  18. 8
      setup.py
  19. 25
      tests/test_basic.py
  20. 30
      tests/test_blueprints.py
  21. 8
      tests/test_cli.py

81
CHANGES.rst

@ -4,10 +4,62 @@ Flask Changelog
=============== ===============
Version 1.1
-----------
Unreleased
Version 1.0.3
-------------
Unreleased
Version 1.0.2
-------------
Released on May 2nd 2018
- Fix more backwards compatibility issues with merging slashes between
a blueprint prefix and route. (`#2748`_)
- Fix error with ``flask routes`` command when there are no routes.
(`#2751`_)
.. _#2748: https://github.com/pallets/flask/pull/2748
.. _#2751: https://github.com/pallets/flask/issues/2751
Version 1.0.1
-------------
Released on April 29th 2018
- Fix registering partials (with no ``__name__``) as view functions.
(`#2730`_)
- Don't treat lists returned from view functions the same as tuples.
Only tuples are interpreted as response data. (`#2736`_)
- Extra slashes between a blueprint's ``url_prefix`` and a route URL
are merged. This fixes some backwards compatibility issues with the
change in 1.0. (`#2731`_, `#2742`_)
- Only trap ``BadRequestKeyError`` errors in debug mode, not all
``BadRequest`` errors. This allows ``abort(400)`` to continue
working as expected. (`#2735`_)
- The ``FLASK_SKIP_DOTENV`` environment variable can be set to ``1``
to skip automatically loading dotenv files. (`#2722`_)
.. _#2722: https://github.com/pallets/flask/issues/2722
.. _#2730: https://github.com/pallets/flask/pull/2730
.. _#2731: https://github.com/pallets/flask/issues/2731
.. _#2735: https://github.com/pallets/flask/issues/2735
.. _#2736: https://github.com/pallets/flask/issues/2736
.. _#2742: https://github.com/pallets/flask/issues/2742
Version 1.0 Version 1.0
----------- -----------
unreleased Released on April 26th 2018
- **Python 2.6 and 3.3 are no longer supported.** (`pallets/meta#24`_) - **Python 2.6 and 3.3 are no longer supported.** (`pallets/meta#24`_)
- Bump minimum dependency versions to the latest stable versions: - Bump minimum dependency versions to the latest stable versions:
@ -215,6 +267,33 @@ unreleased
.. _#2709: https://github.com/pallets/flask/pull/2709 .. _#2709: https://github.com/pallets/flask/pull/2709
Version 0.12.4
--------------
Released on April 29 2018
- Repackage 0.12.3 to fix package layout issue. (`#2728`_)
.. _#2728: https://github.com/pallets/flask/issues/2728
Version 0.12.3
--------------
Released on April 26th 2018
- :func:`Request.get_json` no longer accepts arbitrary encodings.
Incoming JSON should be encoded using UTF-8 per :rfc:`8259`, but
Flask will autodetect UTF-8, -16, or -32. (`#2692`_)
- Fix a Python warning about imports when using ``python -m flask``.
(`#2666`_)
- Fix a ``ValueError`` caused by invalid ``Range`` requests in some
cases.
.. _#2666: https://github.com/pallets/flask/issues/2666
.. _#2692: https://github.com/pallets/flask/issues/2692
Version 0.12.2 Version 0.12.2
-------------- --------------

12
README.rst

@ -43,11 +43,23 @@ A Simple Example
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Donate
------
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, `please
donate today`_.
.. _please donate today: https://psfmember.org/civicrm/contribute/transact?reset=1&id=20
Links Links
----- -----
* Website: https://www.palletsprojects.com/p/flask/ * Website: https://www.palletsprojects.com/p/flask/
* Documentation: http://flask.pocoo.org/docs/ * Documentation: http://flask.pocoo.org/docs/
* License: `BSD <https://github.com/pallets/flask/blob/master/LICENSE>`_
* Releases: https://pypi.org/project/Flask/ * Releases: https://pypi.org/project/Flask/
* Code: https://github.com/pallets/flask * Code: https://github.com/pallets/flask
* Issue tracker: https://github.com/pallets/flask/issues * Issue tracker: https://github.com/pallets/flask/issues

13
docs/api.rst

@ -717,7 +717,18 @@ definition for a URL that accepts an optional page::
pass pass
This specifies that ``/users/`` will be the URL for page one and This specifies that ``/users/`` will be the URL for page one and
``/users/page/N`` will be the URL for page `N`. ``/users/page/N`` will be the URL for page ``N``.
If a URL contains a default value, it will be redirected to its simpler
form with a 301 redirect. In the above example, ``/users/page/1`` will
be redirected to ``/users/``. If your route handles ``GET`` and ``POST``
requests, make sure the default route only handles ``GET``, as redirects
can't preserve form data. ::
@app.route('/region/', defaults={'id': 1})
@app.route('/region/<id>', methods=['GET', 'POST'])
def region(id):
pass
Here are the parameters that :meth:`~flask.Flask.route` and Here are the parameters that :meth:`~flask.Flask.route` and
:meth:`~flask.Flask.add_url_rule` accept. The only difference is that :meth:`~flask.Flask.add_url_rule` accept. The only difference is that

2
docs/blueprints.rst

@ -158,7 +158,7 @@ It is either an absolute path or relative to the blueprint's location::
admin = Blueprint('admin', __name__, static_folder='static') admin = Blueprint('admin', __name__, static_folder='static')
By default the rightmost part of the path is where it is exposed on the By default the rightmost part of the path is where it is exposed on the
web. This can be changed with the ``static_url`` argument. Because the web. This can be changed with the ``static_url_path`` argument. Because the
folder is called ``static`` here it will be available at the folder is called ``static`` here it will be available at the
``url_prefix`` of the blueprint + ``/static``. If the blueprint ``url_prefix`` of the blueprint + ``/static``. If the blueprint
has the prefix ``/admin``, the static URL will be ``/admin/static``. has the prefix ``/admin``, the static URL will be ``/admin/static``.

24
docs/cli.rst

@ -201,6 +201,30 @@ These can be added to the ``.flaskenv`` file just like ``FLASK_APP`` to
control default command options. control default command options.
Disable dotenv
~~~~~~~~~~~~~~
The ``flask`` command will show a message if it detects dotenv files but
python-dotenv is not installed.
.. code-block:: none
flask run
* Tip: There are .env files present. Do "pip install python-dotenv" to use them.
You can tell Flask not to load dotenv files even when python-dotenv is
installed by setting the ``FLASK_SKIP_DOTENV`` environment variable.
This can be useful if you want to load them manually, or if you're using
a project runner that loads them already. Keep in mind that the
environment variables must be set before the app loads or it won't
configure as expected.
.. code-block:: none
export FLASK_SKIP_DOTENV=1
flask run
Environment Variables From virtualenv Environment Variables From virtualenv
------------------------------------- -------------------------------------

2
docs/conf.py

@ -39,6 +39,7 @@ intersphinx_mapping = {
html_theme = 'flask' html_theme = 'flask'
html_context = { html_context = {
'project_links': [ 'project_links': [
ProjectLink('Donate to Pallets', 'https://psfmember.org/civicrm/contribute/transact?reset=1&id=20'),
ProjectLink('Flask Website', 'https://palletsprojects.com/p/flask/'), ProjectLink('Flask Website', 'https://palletsprojects.com/p/flask/'),
ProjectLink('PyPI releases', 'https://pypi.org/project/Flask/'), ProjectLink('PyPI releases', 'https://pypi.org/project/Flask/'),
ProjectLink('Source Code', 'https://github.com/pallets/flask/'), ProjectLink('Source Code', 'https://github.com/pallets/flask/'),
@ -57,6 +58,7 @@ html_sidebars = {
'index': [ 'index': [
'project.html', 'project.html',
'versions.html', 'versions.html',
'carbon_ads.html',
'searchbox.html', 'searchbox.html',
], ],
'**': [ '**': [

2
docs/config.rst

@ -112,7 +112,7 @@ The following configuration values are used internally by Flask:
**Do not enable debug mode when deploying in production.** **Do not enable debug mode when deploying in production.**
Default: ``True`` if :data:`ENV` is ``'production'``, or ``False`` Default: ``True`` if :data:`ENV` is ``'development'``, or ``False``
otherwise. otherwise.
.. py:data:: TESTING .. py:data:: TESTING

8
docs/flaskstyle.sty

@ -1,11 +1,17 @@
\definecolor{TitleColor}{rgb}{0,0,0} \definecolor{TitleColor}{rgb}{0,0,0}
\definecolor{InnerLinkColor}{rgb}{0,0,0} \definecolor{InnerLinkColor}{rgb}{0,0,0}
% Replace Unicode character 'PARTY POPPER' (U+1F389) with a non-breaking space.
% pdfLaTeX doesn't support Unicode.
\DeclareUnicodeCharacter{1F389}{\nobreakspace}
\renewcommand{\maketitle}{% \renewcommand{\maketitle}{%
\begin{titlepage}% \begin{titlepage}%
\let\footnotesize\small \let\footnotesize\small
\let\footnoterule\relax \let\footnoterule\relax
\ifsphinxpdfoutput % Apply following fix only on PDF output, i.e. pdfoutput macro is not
% undefined
\ifx\pdfoutput\undefined\else
\begingroup \begingroup
% This \def is required to deal with multi-line authors; it % This \def is required to deal with multi-line authors; it
% changes \\ to ', ' (comma-space), making it pass muster for % changes \\ to ', ' (comma-space), making it pass muster for

2
docs/patterns/fileuploads.rst

@ -65,7 +65,7 @@ the file and redirects the user to the URL for the uploaded file::
if file and allowed_file(file.filename): if file and allowed_file(file.filename):
filename = secure_filename(file.filename) filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('upload_file', return redirect(url_for('uploaded_file',
filename=filename)) filename=filename))
return ''' return '''
<!doctype html> <!doctype html>

6
docs/quickstart.rst

@ -293,7 +293,7 @@ Python shell. See :ref:`context-locals`. ::
@app.route('/user/<username>') @app.route('/user/<username>')
def profile(username): def profile(username):
return '{}'s profile'.format(username) return '{}\'s profile'.format(username)
with app.test_request_context(): with app.test_request_context():
print(url_for('index')) print(url_for('index'))
@ -315,6 +315,8 @@ a route only answers to ``GET`` requests. You can use the ``methods`` argument
of the :meth:`~flask.Flask.route` decorator to handle different HTTP methods. of the :meth:`~flask.Flask.route` decorator to handle different HTTP methods.
:: ::
from flask import request
@app.route('/login', methods=['GET', 'POST']) @app.route('/login', methods=['GET', 'POST'])
def login(): def login():
if request.method == 'POST': if request.method == 'POST':
@ -323,7 +325,7 @@ of the :meth:`~flask.Flask.route` decorator to handle different HTTP methods.
return show_the_login_form() return show_the_login_form()
If ``GET`` is present, Flask automatically adds support for the ``HEAD`` method If ``GET`` is present, Flask automatically adds support for the ``HEAD`` method
and handles ``HEAD`` requests according to the the `HTTP RFC`_. Likewise, and handles ``HEAD`` requests according to the `HTTP RFC`_. Likewise,
``OPTIONS`` is automatically implemented for you. ``OPTIONS`` is automatically implemented for you.
.. _HTTP RFC: https://www.ietf.org/rfc/rfc2068.txt .. _HTTP RFC: https://www.ietf.org/rfc/rfc2068.txt

2
docs/tutorial/static.rst

@ -55,7 +55,7 @@ the following into the ``flaskr/static/style.css`` file:
You can find a less compact version of ``style.css`` in the You can find a less compact version of ``style.css`` in the
:gh:`example code <examples/tutorial/flaskr/static/style.css>`. :gh:`example code <examples/tutorial/flaskr/static/style.css>`.
Go to http://127.0.0.1/auth/login and the page should look like the Go to http://127.0.0.1:5000/auth/login and the page should look like the
screenshot below. screenshot below.
.. image:: flaskr_login.png .. image:: flaskr_login.png

2
docs/upgrading.rst

@ -215,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/pallets/flask/master/scripts/flask-07-upgrade.py>`_ <https://raw.githubusercontent.com/pallets/flask/0.12.3/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

2
flask/__init__.py

@ -10,7 +10,7 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
__version__ = '1.0-dev' __version__ = '1.1.dev'
# utilities we import from Werkzeug and Jinja2 that are unused # utilities we import from Werkzeug and Jinja2 that are unused
# in the module but are exported as public interface. # in the module but are exported as public interface.

22
flask/app.py

@ -27,9 +27,11 @@ from ._compat import integer_types, reraise, string_types, text_type
from .config import Config, ConfigAttribute from .config import Config, ConfigAttribute
from .ctx import AppContext, RequestContext, _AppCtxGlobals from .ctx import AppContext, RequestContext, _AppCtxGlobals
from .globals import _request_ctx_stack, g, request, session from .globals import _request_ctx_stack, g, request, session
from .helpers import _PackageBoundObject, \ from .helpers import (
_endpoint_from_view_func, find_package, get_env, get_debug_flag, \ _PackageBoundObject,
get_flashed_messages, locked_cached_property, url_for _endpoint_from_view_func, find_package, get_env, get_debug_flag,
get_flashed_messages, locked_cached_property, url_for, get_load_dotenv
)
from .logging import create_logger from .logging import create_logger
from .sessions import SecureCookieSessionInterface from .sessions import SecureCookieSessionInterface
from .signals import appcontext_tearing_down, got_request_exception, \ from .signals import appcontext_tearing_down, got_request_exception, \
@ -904,7 +906,7 @@ class Flask(_PackageBoundObject):
explain_ignored_app_run() explain_ignored_app_run()
return return
if load_dotenv: if get_load_dotenv(load_dotenv):
cli.load_dotenv() cli.load_dotenv()
# if set, let env vars override previous values # if set, let env vars override previous values
@ -1663,8 +1665,14 @@ class Flask(_PackageBoundObject):
trap_bad_request = self.config['TRAP_BAD_REQUEST_ERRORS'] trap_bad_request = self.config['TRAP_BAD_REQUEST_ERRORS']
# if unset, trap based on debug mode # if unset, trap key errors in debug mode
if (trap_bad_request is None and self.debug) or trap_bad_request: if (
trap_bad_request is None and self.debug
and isinstance(e, BadRequestKeyError)
):
return True
if trap_bad_request:
return isinstance(e, BadRequest) return isinstance(e, BadRequest)
return False return False
@ -1923,7 +1931,7 @@ class Flask(_PackageBoundObject):
status = headers = None status = headers = None
# unpack tuple returns # unpack tuple returns
if isinstance(rv, (tuple, list)): if isinstance(rv, tuple):
len_rv = len(rv) len_rv = len(rv)
# a 3-tuple is unpacked directly # a 3-tuple is unpacked directly

15
flask/blueprints.py

@ -10,6 +10,7 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from functools import update_wrapper from functools import update_wrapper
from werkzeug.urls import url_join
from .helpers import _PackageBoundObject, _endpoint_from_view_func from .helpers import _PackageBoundObject, _endpoint_from_view_func
@ -49,12 +50,8 @@ class BlueprintSetupState(object):
url_prefix = self.options.get('url_prefix') url_prefix = self.options.get('url_prefix')
if url_prefix is None: if url_prefix is None:
url_prefix = self.blueprint.url_prefix url_prefix = self.blueprint.url_prefix
#: The prefix that should be used for all URLs defined on the #: The prefix that should be used for all URLs defined on the
#: blueprint. #: blueprint.
if url_prefix and url_prefix[-1] == '/':
url_prefix = url_prefix[:-1]
self.url_prefix = url_prefix self.url_prefix = url_prefix
#: A dictionary with URL defaults that is added to each and every #: A dictionary with URL defaults that is added to each and every
@ -67,8 +64,12 @@ class BlueprintSetupState(object):
to the application. The endpoint is automatically prefixed with the to the application. The endpoint is automatically prefixed with the
blueprint's name. blueprint's name.
""" """
if self.url_prefix: if self.url_prefix is not None:
rule = self.url_prefix + rule if rule:
rule = '/'.join((
self.url_prefix.rstrip('/'), rule.lstrip('/')))
else:
rule = self.url_prefix
options.setdefault('subdomain', self.subdomain) options.setdefault('subdomain', self.subdomain)
if endpoint is None: if endpoint is None:
endpoint = _endpoint_from_view_func(view_func) endpoint = _endpoint_from_view_func(view_func)
@ -201,7 +202,7 @@ class Blueprint(_PackageBoundObject):
""" """
if endpoint: if endpoint:
assert '.' not in endpoint, "Blueprint endpoints should not contain dots" assert '.' not in endpoint, "Blueprint endpoints should not contain dots"
if view_func: if view_func and hasattr(view_func, '__name__'):
assert '.' not in view_func.__name__, "Blueprint view function name should not contain dots" assert '.' not in view_func.__name__, "Blueprint view function name should not contain dots"
self.record(lambda s: self.record(lambda s:
s.add_url_rule(rule, endpoint, view_func, **options)) s.add_url_rule(rule, endpoint, view_func, **options))

11
flask/cli.py

@ -28,7 +28,7 @@ from werkzeug.utils import import_string
from . import __version__ from . import __version__
from ._compat import getargspec, iteritems, reraise, text_type from ._compat import getargspec, iteritems, reraise, text_type
from .globals import current_app from .globals import current_app
from .helpers import get_debug_flag, get_env from .helpers import get_debug_flag, get_env, get_load_dotenv
try: try:
import dotenv import dotenv
@ -544,7 +544,7 @@ class FlaskGroup(AppGroup):
# script that is loaded here also attempts to start a server. # script that is loaded here also attempts to start a server.
os.environ['FLASK_RUN_FROM_CLI'] = 'true' os.environ['FLASK_RUN_FROM_CLI'] = 'true'
if self.load_dotenv: if get_load_dotenv(self.load_dotenv):
load_dotenv() load_dotenv()
obj = kwargs.get('obj') obj = kwargs.get('obj')
@ -583,12 +583,11 @@ def load_dotenv(path=None):
.. versionadded:: 1.0 .. versionadded:: 1.0
""" """
if dotenv is None: if dotenv is None:
if path or os.path.exists('.env') or os.path.exists('.flaskenv'): if path or os.path.exists('.env') or os.path.exists('.flaskenv'):
click.secho( click.secho(
' * Tip: There are .env files present.' ' * Tip: There are .env files present.'
' Do "pip install python-dotenv" to use them', ' Do "pip install python-dotenv" to use them.',
fg='yellow') fg='yellow')
return return
@ -826,6 +825,10 @@ def routes_command(sort, all_methods):
"""Show all registered routes with endpoints and methods.""" """Show all registered routes with endpoints and methods."""
rules = list(current_app.url_map.iter_rules()) rules = list(current_app.url_map.iter_rules())
if not rules:
click.echo('No routes were registered.')
return
ignored_methods = set(() if all_methods else ('HEAD', 'OPTIONS')) ignored_methods = set(() if all_methods else ('HEAD', 'OPTIONS'))
if sort in ('endpoint', 'rule'): if sort in ('endpoint', 'rule'):

15
flask/helpers.py

@ -68,6 +68,21 @@ def get_debug_flag():
return val.lower() not in ('0', 'false', 'no') return val.lower() not in ('0', 'false', 'no')
def get_load_dotenv(default=True):
"""Get whether the user has disabled loading dotenv files by setting
:envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load the
files.
:param default: What to return if the env var isn't set.
"""
val = os.environ.get('FLASK_SKIP_DOTENV')
if not val:
return default
return val.lower() in ('0', 'false', 'no')
def _endpoint_from_view_func(view_func): def _endpoint_from_view_func(view_func):
"""Internal helper that returns the default endpoint for a given """Internal helper that returns the default endpoint for a given
function. This always is the function name. function. This always is the function name.

8
setup.py

@ -2,6 +2,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import io import io
import re import re
from collections import OrderedDict
from setuptools import setup from setuptools import setup
with io.open('README.rst', 'rt', encoding='utf8') as f: with io.open('README.rst', 'rt', encoding='utf8') as f:
@ -14,6 +16,11 @@ setup(
name='Flask', name='Flask',
version=version, version=version,
url='https://www.palletsprojects.com/p/flask/', url='https://www.palletsprojects.com/p/flask/',
project_urls=OrderedDict((
('Documentation', 'http://flask.pocoo.org/docs/'),
('Code', 'https://github.com/pallets/flask'),
('Issue tracker', 'https://github.com/pallets/flask/issues'),
)),
license='BSD', license='BSD',
author='Armin Ronacher', author='Armin Ronacher',
author_email='armin.ronacher@active-4.com', author_email='armin.ronacher@active-4.com',
@ -25,6 +32,7 @@ setup(
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',

25
tests/test_basic.py

@ -1027,21 +1027,34 @@ def test_errorhandler_precedence(app, client):
def test_trapping_of_bad_request_key_errors(app, client): def test_trapping_of_bad_request_key_errors(app, client):
@app.route('/fail') @app.route('/key')
def fail(): def fail():
flask.request.form['missing_key'] flask.request.form['missing_key']
rv = client.get('/fail') @app.route('/abort')
def allow_abort():
flask.abort(400)
rv = client.get('/key')
assert rv.status_code == 400 assert rv.status_code == 400
assert b'missing_key' not in rv.data assert b'missing_key' not in rv.data
rv = client.get('/abort')
assert rv.status_code == 400
app.config['TRAP_BAD_REQUEST_ERRORS'] = True app.debug = True
with pytest.raises(KeyError) as e: with pytest.raises(KeyError) as e:
client.get("/fail") client.get("/key")
assert e.errisinstance(BadRequest) assert e.errisinstance(BadRequest)
assert 'missing_key' in e.value.description assert 'missing_key' in e.value.description
rv = client.get('/abort')
assert rv.status_code == 400
app.debug = False
app.config['TRAP_BAD_REQUEST_ERRORS'] = True
with pytest.raises(KeyError):
client.get('/key')
with pytest.raises(BadRequest):
client.get('/abort')
def test_trapping_of_all_http_exceptions(app, client): def test_trapping_of_all_http_exceptions(app, client):

30
tests/test_blueprints.py

@ -9,6 +9,7 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import functools
import pytest import pytest
import flask import flask
@ -114,17 +115,28 @@ def test_blueprint_app_error_handling(app, client):
assert client.get('/nope').data == b'you shall not pass' assert client.get('/nope').data == b'you shall not pass'
def test_blueprint_prefix_slash(app, client): @pytest.mark.parametrize(('prefix', 'rule', 'url'), (
bp = flask.Blueprint('test', __name__, url_prefix='/bar/') ('', '/', '/'),
('/', '', '/'),
@bp.route('/foo') ('/', '/', '/'),
def foo(): ('/foo', '', '/foo'),
('/foo/', '', '/foo/'),
('', '/bar', '/bar'),
('/foo/', '/bar', '/foo/bar'),
('/foo/', 'bar', '/foo/bar'),
('/foo', '/bar', '/foo/bar'),
('/foo/', '//bar', '/foo/bar'),
('/foo//', '/bar', '/foo/bar'),
))
def test_blueprint_prefix_slash(app, client, prefix, rule, url):
bp = flask.Blueprint('test', __name__, url_prefix=prefix)
@bp.route(rule)
def index():
return '', 204 return '', 204
app.register_blueprint(bp) app.register_blueprint(bp)
app.register_blueprint(bp, url_prefix='/spam/') assert client.get(url).status_code == 204
assert client.get('/bar/foo').status_code == 204
assert client.get('/spam/foo').status_code == 204
def test_blueprint_url_defaults(app, client): def test_blueprint_url_defaults(app, client):
@ -382,6 +394,8 @@ def test_route_decorator_custom_endpoint_with_dots(app, client):
) )
) )
bp.add_url_rule('/bar/456', endpoint='foofoofoo', view_func=functools.partial(foo_foo_foo))
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert client.get('/py/foo').data == b'bp.foo' assert client.get('/py/foo').data == b'bp.foo'

8
tests/test_cli.py

@ -474,6 +474,14 @@ def test_dotenv_optional(monkeypatch):
assert 'FOO' not in os.environ assert 'FOO' not in os.environ
@need_dotenv
def test_disable_dotenv_from_env(monkeypatch, runner):
monkeypatch.chdir(test_path)
monkeypatch.setitem(os.environ, 'FLASK_SKIP_DOTENV', '1')
runner.invoke(FlaskGroup())
assert 'FOO' not in os.environ
def test_run_cert_path(): def test_run_cert_path():
# no key # no key
with pytest.raises(click.BadParameter): with pytest.raises(click.BadParameter):

Loading…
Cancel
Save