Browse Source

Merge branch '1.0-maintenance'

pull/2828/head
ThiefMaster 6 years ago
parent
commit
161c43649d
  1. 11
      .appveyor.yml
  2. 23
      .travis.yml
  3. 9
      CHANGES.rst
  4. 5
      docs/installation.rst
  5. 27
      flask/cli.py
  6. 8
      flask/helpers.py
  7. 26
      tests/test_cli.py
  8. 23
      tests/test_helpers.py
  9. 2
      tox.ini

11
.appveyor.yml

@ -1,16 +1,16 @@
environment:
global:
TOXENV: py
TOXENV: py,codecov
matrix:
- PYTHON: C:\Python36
- PYTHON: C:\Python27
- PYTHON: C:\Python36-x64
- PYTHON: C:\Python27-x64
init:
- SET PATH=%PYTHON%;%PATH%
install:
- python -m pip install -U pip setuptools wheel tox
- python -m pip install -U tox
build: false
@ -21,3 +21,6 @@ branches:
only:
- master
- /^.*-maintenance$/
cache:
- '%LOCALAPPDATA%\pip\Cache'

23
.travis.yml

@ -14,27 +14,30 @@ matrix:
env: TOXENV=py,codecov
- python: 2.7
env: TOXENV=py,simplejson,devel,lowest,codecov
- python: pypy
- python: pypy3
env: TOXENV=py,codecov
- python: nightly
env: TOXENV=py
- os: osx
language: generic
env: TOXENV=py
env: TOXENV=py3,py2,codecov
cache:
pip: false
directories:
- $HOME/Library/Caches/Homebrew
- $HOME/Library/Caches/pip
allow_failures:
- python: pypy3
- python: nightly
env: TOXENV=py
- os: osx
language: generic
env: TOXENV=py
fast_finish: true
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew update;
brew install python3 redis memcached;
virtualenv -p python3 ~/py-env;
. ~/py-env/bin/activate;
- |
if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
brew upgrade python
brew install python@2;
export PATH="/usr/local/opt/python/libexec/bin:${PATH}"
fi
install:

9
CHANGES.rst

@ -15,6 +15,15 @@ Version 1.0.3
Unreleased
- :func:`send_file` encodes filenames as ASCII instead of Latin-1
(ISO-8859-1). This fixes compatibility with Gunicorn, which is
stricter about header encodings than PEP 3333. (`#2766`_)
- Allow custom CLIs using ``FlaskGroup`` to set the debug flag without
it always being overwritten based on environment variables. (`#2765`_)
.. _#2766: https://github.com/pallets/flask/issues/2766
.. _#2765: https://github.com/pallets/flask/pull/2765
Version 1.0.2
-------------

5
docs/installation.rst

@ -132,6 +132,9 @@ Within the activated environment, use the following command to install Flask:
pip install Flask
Flask is now installed. Check out the :doc:`/quickstart` or go to the
:doc:`Documentation Overview </index>`.
Living on the edge
~~~~~~~~~~~~~~~~~~
@ -177,7 +180,7 @@ On Windows, as an administrator:
\Python27\python.exe Downloads\get-pip.py
\Python27\python.exe -m pip install virtualenv
Now you can continue to :ref:`install-create-env`.
Now you can return above and :ref:`install-create-env`.
.. _virtualenv: https://virtualenv.pypa.io/
.. _get-pip.py: https://bootstrap.pypa.io/get-pip.py

27
flask/cli.py

@ -340,7 +340,8 @@ class ScriptInfo(object):
onwards as click object.
"""
def __init__(self, app_import_path=None, create_app=None):
def __init__(self, app_import_path=None, create_app=None,
set_debug_flag=True):
#: Optionally the import path for the Flask application.
self.app_import_path = app_import_path or os.environ.get('FLASK_APP')
#: Optionally a function that is passed the script info to create
@ -349,6 +350,7 @@ class ScriptInfo(object):
#: A dictionary with arbitrary data that can be associated with
#: this script info.
self.data = {}
self.set_debug_flag = set_debug_flag
self._loaded_app = None
def load_app(self):
@ -386,12 +388,10 @@ class ScriptInfo(object):
'"app.py" module was not found in the current directory.'
)
debug = get_debug_flag()
# Update the app's debug flag through the descriptor so that other
# values repopulate as well.
if debug is not None:
app.debug = debug
if self.set_debug_flag:
# Update the app's debug flag through the descriptor so that
# other values repopulate as well.
app.debug = get_debug_flag()
self._loaded_app = app
return app
@ -459,6 +459,8 @@ class FlaskGroup(AppGroup):
:param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
files to set environment variables. Will also change the working
directory to the directory containing the first file found.
:param set_debug_flag: Set the app's debug flag based on the active
environment
.. versionchanged:: 1.0
If installed, python-dotenv will be used to load environment variables
@ -466,7 +468,8 @@ class FlaskGroup(AppGroup):
"""
def __init__(self, add_default_commands=True, create_app=None,
add_version_option=True, load_dotenv=True, **extra):
add_version_option=True, load_dotenv=True,
set_debug_flag=True, **extra):
params = list(extra.pop('params', None) or ())
if add_version_option:
@ -475,6 +478,7 @@ class FlaskGroup(AppGroup):
AppGroup.__init__(self, params=params, **extra)
self.create_app = create_app
self.load_dotenv = load_dotenv
self.set_debug_flag = set_debug_flag
if add_default_commands:
self.add_command(run_command)
@ -550,7 +554,8 @@ class FlaskGroup(AppGroup):
obj = kwargs.get('obj')
if obj is None:
obj = ScriptInfo(create_app=self.create_app)
obj = ScriptInfo(create_app=self.create_app,
set_debug_flag=self.set_debug_flag)
kwargs['obj'] = obj
kwargs.setdefault('auto_envvar_prefix', 'FLASK')
@ -670,7 +675,7 @@ class CertParamType(click.ParamType):
obj = import_string(value, silent=True)
if sys.version_info < (2, 7):
if sys.version_info < (2, 7, 9):
if obj:
return obj
else:
@ -687,7 +692,7 @@ def _validate_key(ctx, param, value):
cert = ctx.params.get('cert')
is_adhoc = cert == 'adhoc'
if sys.version_info < (2, 7):
if sys.version_info < (2, 7, 9):
is_context = cert and not isinstance(cert, (text_type, bytes))
else:
is_context = isinstance(cert, ssl.SSLContext)

8
flask/helpers.py

@ -506,6 +506,10 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
.. _RFC 2231: https://tools.ietf.org/html/rfc2231#section-4
.. versionchanged:: 1.0.3
Filenames are encoded with ASCII instead of Latin-1 for broader
compatibility with WSGI servers.
:param filename_or_fp: the filename of the file to send.
This is relative to the :attr:`~Flask.root_path`
if a relative path is specified.
@ -564,11 +568,11 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
'sending as attachment')
try:
attachment_filename = attachment_filename.encode('latin-1')
attachment_filename = attachment_filename.encode('ascii')
except UnicodeEncodeError:
filenames = {
'filename': unicodedata.normalize(
'NFKD', attachment_filename).encode('latin-1', 'ignore'),
'NFKD', attachment_filename).encode('ascii', 'ignore'),
'filename*': "UTF-8''%s" % url_quote(attachment_filename),
}
else:

26
tests/test_cli.py

@ -356,6 +356,28 @@ def test_flaskgroup(runner):
assert result.output == 'flaskgroup\n'
@pytest.mark.parametrize('set_debug_flag', (True, False))
def test_flaskgroup_debug(runner, set_debug_flag):
"""Test FlaskGroup debug flag behavior."""
def create_app(info):
app = Flask("flaskgroup")
app.debug = True
return app
@click.group(cls=FlaskGroup, create_app=create_app, set_debug_flag=set_debug_flag)
def cli(**params):
pass
@cli.command()
def test():
click.echo(str(current_app.debug))
result = runner.invoke(cli, ['test'])
assert result.exit_code == 0
assert result.output == '%s\n' % str(not set_debug_flag)
def test_print_exceptions(runner):
"""Print the stacktrace if the CLI."""
@ -537,12 +559,12 @@ def test_run_cert_import(monkeypatch):
run_command.make_context('run', ['--cert', 'not_here'])
# not an SSLContext
if sys.version_info >= (2, 7):
if sys.version_info >= (2, 7, 9):
with pytest.raises(click.BadParameter):
run_command.make_context('run', ['--cert', 'flask'])
# SSLContext
if sys.version_info < (2, 7):
if sys.version_info < (2, 7, 9):
ssl_context = object()
else:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

23
tests/test_helpers.py

@ -638,15 +638,22 @@ class TestSendfile(object):
assert options['filename'] == 'index.txt'
rv.close()
def test_attachment_with_utf8_filename(self, app, req_ctx):
rv = flask.send_file('static/index.html', as_attachment=True, attachment_filename=u'Ñandú/pingüino.txt')
content_disposition = set(rv.headers['Content-Disposition'].split('; '))
assert content_disposition == set((
'attachment',
'filename="Nandu/pinguino.txt"',
"filename*=UTF-8''%C3%91and%C3%BA%EF%BC%8Fping%C3%BCino.txt"
))
@pytest.mark.usefixtures('req_ctx')
@pytest.mark.parametrize(('filename', 'ascii', 'utf8'), (
('index.html', 'index.html', False),
(u'Ñandú/pingüino.txt', '"Nandu/pinguino.txt"',
'%C3%91and%C3%BA%EF%BC%8Fping%C3%BCino.txt'),
(u'Vögel.txt', 'Vogel.txt', 'V%C3%B6gel.txt'),
))
def test_attachment_filename_encoding(self, filename, ascii, utf8):
rv = flask.send_file('static/index.html', as_attachment=True, attachment_filename=filename)
rv.close()
content_disposition = rv.headers['Content-Disposition']
assert 'filename=%s' % ascii in content_disposition
if utf8:
assert "filename*=UTF-8''" + utf8 in content_disposition
else:
assert "filename*=UTF-8''" not in content_disposition
def test_static_file(self, app, req_ctx):
# default cache timeout is 12 hours

2
tox.ini

@ -60,7 +60,7 @@ commands =
coverage html
[testenv:codecov]
passenv = CI TRAVIS TRAVIS_*
passenv = CI TRAVIS TRAVIS_* APPVEYOR APPVEYOR_*
deps = codecov
skip_install = true
commands =

Loading…
Cancel
Save