mirror of https://github.com/pallets/flask.git
Fixes for PEP451 import loaders and pytest 5.x
- pytest 5.x drops python2 compatibility and therefore only implements PEP 451 - pytest 5.x made the repr of `ExcInfo` less confusing (fixed tests depending on the old format)
This commit is contained in:
parent
b9c2267272
commit
a5ecdfa7a5
|
@ -10,6 +10,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.
|
||||||
|
|
|
@ -12,7 +12,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):
|
||||||
|
|
|
@ -789,19 +789,38 @@ def _matching_loader_thinks_module_is_package(loader, mod_name):
|
||||||
loader.__class__.__name__)
|
loader.__class__.__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'):
|
||||||
|
@ -815,17 +834,29 @@ 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
|
||||||
# rightmost part. This needs to go through a helper function
|
# rightmost part. This needs to go through a helper function
|
||||||
# because of python 3.3 namespace packages.
|
# because of python 3.3 namespace packages.
|
||||||
if _matching_loader_thinks_module_is_package(
|
if _matching_loader_thinks_module_is_package(loader, root_mod_name):
|
||||||
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):
|
||||||
|
|
|
@ -1219,17 +1219,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)
|
assert 'returned None' in str(e.value)
|
||||||
|
|
||||||
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)
|
assert 'tuple must have the form' in str(e.value)
|
||||||
|
|
||||||
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)
|
assert 'it was a bool' in str(e.value)
|
||||||
|
|
||||||
pytest.raises(TypeError, c.get, '/bad_wsgi')
|
pytest.raises(TypeError, c.get, '/bad_wsgi')
|
||||||
|
|
||||||
|
@ -1622,7 +1622,7 @@ def test_debug_mode_complains_after_first_request(app, client):
|
||||||
@app.route('/foo')
|
@app.route('/foo')
|
||||||
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
|
||||||
|
|
||||||
|
@ -1677,9 +1677,9 @@ 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 '
|
assert ('Make sure to directly send '
|
||||||
'your POST-request to this URL') in str(e)
|
'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'
|
||||||
|
|
|
@ -468,8 +468,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…
Reference in New Issue