Add support for PathLike objects in static file helpers

See: https://www.python.org/dev/peps/pep-0519/

This is mostly encountered with pathlib in python 3, but this API
suggests any PathLike object can be treated like a filepath with
`__fspath__` function.
This commit is contained in:
Matt Robenolt 2019-01-03 17:17:45 -08:00 committed by David Lord
parent f7d50d4b67
commit 25de45cbb6
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8
4 changed files with 62 additions and 5 deletions

View file

@ -97,3 +97,12 @@ if hasattr(sys, 'pypy_version_info'):
BROKEN_PYPY_CTXMGR_EXIT = True
except AssertionError:
pass
try:
from os import fspath
except ImportError:
# Backwards compatibility as proposed in PEP 0519:
# https://www.python.org/dev/peps/pep-0519/#backwards-compatibility
def fspath(path):
return path.__fspath__() if hasattr(path, '__fspath__') else path

View file

@ -33,7 +33,7 @@ from jinja2 import FileSystemLoader
from .signals import message_flashed
from .globals import session, _request_ctx_stack, _app_ctx_stack, \
current_app, request
from ._compat import string_types, text_type, PY2
from ._compat import string_types, text_type, PY2, fspath
# sentinel
_missing = object()
@ -510,6 +510,9 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
Filenames are encoded with ASCII instead of Latin-1 for broader
compatibility with WSGI servers.
.. versionchanged:: 1.1
Filenames may be a `PathLike` object.
: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.
@ -538,6 +541,10 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
"""
mtime = None
fsize = None
if hasattr(filename_or_fp, '__fspath__'):
filename_or_fp = fspath(filename_or_fp)
if isinstance(filename_or_fp, string_types):
filename = filename_or_fp
if not os.path.isabs(filename):
@ -705,6 +712,8 @@ def send_from_directory(directory, filename, **options):
:param options: optional keyword arguments that are directly
forwarded to :func:`send_file`.
"""
filename = fspath(filename)
directory = fspath(directory)
filename = safe_join(directory, filename)
if not os.path.isabs(filename):
filename = os.path.join(current_app.root_path, filename)