Merge branch '1.0.x'
This commit is contained in:
commit
b05a685a03
6 changed files with 59 additions and 28 deletions
|
|
@ -94,6 +94,7 @@ Unreleased
|
||||||
requires upgrading to Werkzeug 0.15.5. :issue:`3249`
|
requires upgrading to Werkzeug 0.15.5. :issue:`3249`
|
||||||
- ``send_file`` url quotes the ":" and "/" characters for more
|
- ``send_file`` url quotes the ":" and "/" characters for more
|
||||||
compatible UTF-8 filename support in some browsers. :issue:`3074`
|
compatible UTF-8 filename support in some browsers. :issue:`3074`
|
||||||
|
- Fixes for PEP451 import loaders and pytest 5.x. :issue:`3275`
|
||||||
|
|
||||||
|
|
||||||
Version 1.0.3
|
Version 1.0.3
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ should be closed.
|
||||||
with pytest.raises(sqlite3.ProgrammingError) as e:
|
with pytest.raises(sqlite3.ProgrammingError) as e:
|
||||||
db.execute('SELECT 1')
|
db.execute('SELECT 1')
|
||||||
|
|
||||||
assert 'closed' in str(e)
|
assert 'closed' in str(e.value)
|
||||||
|
|
||||||
The ``init-db`` command should call the ``init_db`` function and output
|
The ``init-db`` command should call the ``init_db`` function and output
|
||||||
a message.
|
a message.
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ def test_get_close_db(app):
|
||||||
with pytest.raises(sqlite3.ProgrammingError) as e:
|
with pytest.raises(sqlite3.ProgrammingError) as e:
|
||||||
db.execute("SELECT 1")
|
db.execute("SELECT 1")
|
||||||
|
|
||||||
assert "closed" in str(e)
|
assert "closed" in str(e.value)
|
||||||
|
|
||||||
|
|
||||||
def test_init_db_command(runner, monkeypatch):
|
def test_init_db_command(runner, monkeypatch):
|
||||||
|
|
|
||||||
|
|
@ -610,7 +610,7 @@ def send_file(
|
||||||
"filename": unicodedata.normalize("NFKD", attachment_filename).encode(
|
"filename": unicodedata.normalize("NFKD", attachment_filename).encode(
|
||||||
"ascii", "ignore"
|
"ascii", "ignore"
|
||||||
),
|
),
|
||||||
'filename*': "UTF-8''%s" % url_quote(attachment_filename, safe=b""),
|
"filename*": "UTF-8''%s" % url_quote(attachment_filename, safe=b""),
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
filenames = {"filename": attachment_filename}
|
filenames = {"filename": attachment_filename}
|
||||||
|
|
@ -847,19 +847,38 @@ def _matching_loader_thinks_module_is_package(loader, mod_name):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def find_package(import_name):
|
def _find_package_path(root_mod_name):
|
||||||
"""Finds a package and returns the prefix (or None if the package is
|
"""Find the path where the module's root exists in"""
|
||||||
not installed) as well as the folder that contains the package or
|
if sys.version_info >= (3, 4):
|
||||||
module as a tuple. The package path returned is the module that would
|
import importlib.util
|
||||||
have to be added to the pythonpath in order to make it possible to
|
|
||||||
import the module. The prefix is the path below which a UNIX like
|
try:
|
||||||
folder structure exists (lib, share etc.).
|
spec = importlib.util.find_spec(root_mod_name)
|
||||||
"""
|
if spec is None:
|
||||||
root_mod_name = import_name.split(".")[0]
|
raise ValueError("not found")
|
||||||
|
# ImportError: the machinery told us it does not exist
|
||||||
|
# ValueError:
|
||||||
|
# - the module name was invalid
|
||||||
|
# - the module name is __main__
|
||||||
|
# - *we* raised `ValueError` due to `spec` being `None`
|
||||||
|
except (ImportError, ValueError):
|
||||||
|
pass # handled below
|
||||||
|
else:
|
||||||
|
# namespace package
|
||||||
|
if spec.origin in {"namespace", None}:
|
||||||
|
return os.path.dirname(next(iter(spec.submodule_search_locations)))
|
||||||
|
# a package (with __init__.py)
|
||||||
|
elif spec.submodule_search_locations:
|
||||||
|
return os.path.dirname(os.path.dirname(spec.origin))
|
||||||
|
# just a normal module
|
||||||
|
else:
|
||||||
|
return os.path.dirname(spec.origin)
|
||||||
|
|
||||||
|
# we were unable to find the `package_path` using PEP 451 loaders
|
||||||
loader = pkgutil.get_loader(root_mod_name)
|
loader = pkgutil.get_loader(root_mod_name)
|
||||||
if loader is None or import_name == "__main__":
|
if loader is None or root_mod_name == "__main__":
|
||||||
# import name is not found, or interactive/main module
|
# import name is not found, or interactive/main module
|
||||||
package_path = os.getcwd()
|
return os.getcwd()
|
||||||
else:
|
else:
|
||||||
# For .egg, zipimporter does not have get_filename until Python 2.7.
|
# For .egg, zipimporter does not have get_filename until Python 2.7.
|
||||||
if hasattr(loader, "get_filename"):
|
if hasattr(loader, "get_filename"):
|
||||||
|
|
@ -873,8 +892,8 @@ def find_package(import_name):
|
||||||
# Google App Engine's HardenedModulesHook
|
# Google App Engine's HardenedModulesHook
|
||||||
#
|
#
|
||||||
# Fall back to imports.
|
# Fall back to imports.
|
||||||
__import__(import_name)
|
__import__(root_mod_name)
|
||||||
filename = sys.modules[import_name].__file__
|
filename = sys.modules[root_mod_name].__file__
|
||||||
package_path = os.path.abspath(os.path.dirname(filename))
|
package_path = os.path.abspath(os.path.dirname(filename))
|
||||||
|
|
||||||
# In case the root module is a package we need to chop of the
|
# In case the root module is a package we need to chop of the
|
||||||
|
|
@ -883,6 +902,19 @@ def find_package(import_name):
|
||||||
if _matching_loader_thinks_module_is_package(loader, root_mod_name):
|
if _matching_loader_thinks_module_is_package(loader, root_mod_name):
|
||||||
package_path = os.path.dirname(package_path)
|
package_path = os.path.dirname(package_path)
|
||||||
|
|
||||||
|
return package_path
|
||||||
|
|
||||||
|
|
||||||
|
def find_package(import_name):
|
||||||
|
"""Finds a package and returns the prefix (or None if the package is
|
||||||
|
not installed) as well as the folder that contains the package or
|
||||||
|
module as a tuple. The package path returned is the module that would
|
||||||
|
have to be added to the pythonpath in order to make it possible to
|
||||||
|
import the module. The prefix is the path below which a UNIX like
|
||||||
|
folder structure exists (lib, share etc.).
|
||||||
|
"""
|
||||||
|
root_mod_name, _, _ = import_name.partition(".")
|
||||||
|
package_path = _find_package_path(root_mod_name)
|
||||||
site_parent, site_folder = os.path.split(package_path)
|
site_parent, site_folder = os.path.split(package_path)
|
||||||
py_prefix = os.path.abspath(sys.prefix)
|
py_prefix = os.path.abspath(sys.prefix)
|
||||||
if package_path.startswith(py_prefix):
|
if package_path.startswith(py_prefix):
|
||||||
|
|
|
||||||
|
|
@ -1220,21 +1220,17 @@ def test_response_type_errors():
|
||||||
|
|
||||||
with pytest.raises(TypeError) as e:
|
with pytest.raises(TypeError) as e:
|
||||||
c.get("/none")
|
c.get("/none")
|
||||||
|
assert "returned None" in str(e.value)
|
||||||
assert "returned None" in str(e)
|
|
||||||
|
|
||||||
with pytest.raises(TypeError) as e:
|
with pytest.raises(TypeError) as e:
|
||||||
c.get("/small_tuple")
|
c.get("/small_tuple")
|
||||||
|
assert "tuple must have the form" in str(e.value)
|
||||||
assert "tuple must have the form" in str(e)
|
|
||||||
|
|
||||||
pytest.raises(TypeError, c.get, "/large_tuple")
|
pytest.raises(TypeError, c.get, "/large_tuple")
|
||||||
|
|
||||||
with pytest.raises(TypeError) as e:
|
with pytest.raises(TypeError) as e:
|
||||||
c.get("/bad_type")
|
c.get("/bad_type")
|
||||||
|
assert "it was a bool" in str(e.value)
|
||||||
assert "object is not callable" not in str(e)
|
|
||||||
assert "it was a bool" in str(e)
|
|
||||||
|
|
||||||
pytest.raises(TypeError, c.get, "/bad_wsgi")
|
pytest.raises(TypeError, c.get, "/bad_wsgi")
|
||||||
|
|
||||||
|
|
@ -1636,7 +1632,7 @@ def test_debug_mode_complains_after_first_request(app, client):
|
||||||
def broken():
|
def broken():
|
||||||
return "Meh"
|
return "Meh"
|
||||||
|
|
||||||
assert "A setup function was called" in str(e)
|
assert "A setup function was called" in str(e.value)
|
||||||
|
|
||||||
app.debug = False
|
app.debug = False
|
||||||
|
|
||||||
|
|
@ -1691,8 +1687,10 @@ def test_routing_redirect_debugging(app, client):
|
||||||
with client:
|
with client:
|
||||||
with pytest.raises(AssertionError) as e:
|
with pytest.raises(AssertionError) as e:
|
||||||
client.post("/foo", data={})
|
client.post("/foo", data={})
|
||||||
assert "http://localhost/foo/" in str(e)
|
assert "http://localhost/foo/" in str(e.value)
|
||||||
assert ("Make sure to directly send your POST-request to this URL") in str(e)
|
assert ("Make sure to directly send your POST-request to this URL") in str(
|
||||||
|
e.value
|
||||||
|
)
|
||||||
|
|
||||||
rv = client.get("/foo", data={}, follow_redirects=True)
|
rv = client.get("/foo", data={}, follow_redirects=True)
|
||||||
assert rv.data == b"success"
|
assert rv.data == b"success"
|
||||||
|
|
|
||||||
|
|
@ -483,8 +483,8 @@ class TestSendfile(object):
|
||||||
def test_send_file_object_without_mimetype(self, app, req_ctx):
|
def test_send_file_object_without_mimetype(self, app, req_ctx):
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
flask.send_file(StringIO("LOL"))
|
flask.send_file(StringIO("LOL"))
|
||||||
assert "Unable to infer MIME-type" in str(excinfo)
|
assert "Unable to infer MIME-type" in str(excinfo.value)
|
||||||
assert "no filename is available" in str(excinfo)
|
assert "no filename is available" in str(excinfo.value)
|
||||||
|
|
||||||
flask.send_file(StringIO("LOL"), attachment_filename="filename")
|
flask.send_file(StringIO("LOL"), attachment_filename="filename")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue