Merge pull request #2395 from davidism/remove-ext
Remove deprecated flask.ext
This commit is contained in:
commit
bce8ec75eb
6 changed files with 4 additions and 495 deletions
3
CHANGES
3
CHANGES
|
|
@ -84,6 +84,9 @@ Major release, unreleased
|
||||||
if ``app.jinja_env`` was already accessed. (`#2373`_)
|
if ``app.jinja_env`` was already accessed. (`#2373`_)
|
||||||
- The following old deprecated code was removed. (`#2385`_)
|
- The following old deprecated code was removed. (`#2385`_)
|
||||||
|
|
||||||
|
- ``flask.ext`` - import extensions directly by their name instead of
|
||||||
|
through the ``flask.ext`` namespace. For example,
|
||||||
|
``import flask.ext.sqlalchemy`` becomes ``import flask_sqlalchemy``.
|
||||||
- ``Flask.init_jinja_globals`` - extend ``Flask.create_jinja_environment``
|
- ``Flask.init_jinja_globals`` - extend ``Flask.create_jinja_environment``
|
||||||
instead.
|
instead.
|
||||||
- ``Flask.error_handlers`` - tracked by ``Flask.error_handler_spec``,
|
- ``Flask.error_handlers`` - tracked by ``Flask.error_handler_spec``,
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
flask.ext
|
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
Redirect imports for extensions. This module basically makes it possible
|
|
||||||
for us to transition from flaskext.foo to flask_foo without having to
|
|
||||||
force all extensions to upgrade at the same time.
|
|
||||||
|
|
||||||
When a user does ``from flask.ext.foo import bar`` it will attempt to
|
|
||||||
import ``from flask_foo import bar`` first and when that fails it will
|
|
||||||
try to import ``from flaskext.foo import bar``.
|
|
||||||
|
|
||||||
We're switching from namespace packages because it was just too painful for
|
|
||||||
everybody involved.
|
|
||||||
|
|
||||||
:copyright: (c) 2015 by Armin Ronacher.
|
|
||||||
:license: BSD, see LICENSE for more details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def setup():
|
|
||||||
from ..exthook import ExtensionImporter
|
|
||||||
importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], __name__)
|
|
||||||
importer.install()
|
|
||||||
|
|
||||||
|
|
||||||
setup()
|
|
||||||
del setup
|
|
||||||
143
flask/exthook.py
143
flask/exthook.py
|
|
@ -1,143 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
flask.exthook
|
|
||||||
~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Redirect imports for extensions. This module basically makes it possible
|
|
||||||
for us to transition from flaskext.foo to flask_foo without having to
|
|
||||||
force all extensions to upgrade at the same time.
|
|
||||||
|
|
||||||
When a user does ``from flask.ext.foo import bar`` it will attempt to
|
|
||||||
import ``from flask_foo import bar`` first and when that fails it will
|
|
||||||
try to import ``from flaskext.foo import bar``.
|
|
||||||
|
|
||||||
We're switching from namespace packages because it was just too painful for
|
|
||||||
everybody involved.
|
|
||||||
|
|
||||||
This is used by `flask.ext`.
|
|
||||||
|
|
||||||
:copyright: (c) 2015 by Armin Ronacher.
|
|
||||||
:license: BSD, see LICENSE for more details.
|
|
||||||
"""
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import warnings
|
|
||||||
from ._compat import reraise
|
|
||||||
|
|
||||||
|
|
||||||
class ExtDeprecationWarning(DeprecationWarning):
|
|
||||||
pass
|
|
||||||
|
|
||||||
warnings.simplefilter('always', ExtDeprecationWarning)
|
|
||||||
|
|
||||||
|
|
||||||
class ExtensionImporter(object):
|
|
||||||
"""This importer redirects imports from this submodule to other locations.
|
|
||||||
This makes it possible to transition from the old flaskext.name to the
|
|
||||||
newer flask_name without people having a hard time.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module_choices, wrapper_module):
|
|
||||||
self.module_choices = module_choices
|
|
||||||
self.wrapper_module = wrapper_module
|
|
||||||
self.prefix = wrapper_module + '.'
|
|
||||||
self.prefix_cutoff = wrapper_module.count('.') + 1
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.__class__.__module__ == other.__class__.__module__ and \
|
|
||||||
self.__class__.__name__ == other.__class__.__name__ and \
|
|
||||||
self.wrapper_module == other.wrapper_module and \
|
|
||||||
self.module_choices == other.module_choices
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
return not self.__eq__(other)
|
|
||||||
|
|
||||||
def install(self):
|
|
||||||
sys.meta_path[:] = [x for x in sys.meta_path if self != x] + [self]
|
|
||||||
|
|
||||||
def find_module(self, fullname, path=None):
|
|
||||||
if fullname.startswith(self.prefix) and \
|
|
||||||
fullname != 'flask.ext.ExtDeprecationWarning':
|
|
||||||
return self
|
|
||||||
|
|
||||||
def load_module(self, fullname):
|
|
||||||
if fullname in sys.modules:
|
|
||||||
return sys.modules[fullname]
|
|
||||||
|
|
||||||
modname = fullname.split('.', self.prefix_cutoff)[self.prefix_cutoff]
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"Importing flask.ext.{x} is deprecated, use flask_{x} instead."
|
|
||||||
.format(x=modname), ExtDeprecationWarning, stacklevel=2
|
|
||||||
)
|
|
||||||
|
|
||||||
for path in self.module_choices:
|
|
||||||
realname = path % modname
|
|
||||||
try:
|
|
||||||
__import__(realname)
|
|
||||||
except ImportError:
|
|
||||||
exc_type, exc_value, tb = sys.exc_info()
|
|
||||||
# since we only establish the entry in sys.modules at the
|
|
||||||
# very this seems to be redundant, but if recursive imports
|
|
||||||
# happen we will call into the move import a second time.
|
|
||||||
# On the second invocation we still don't have an entry for
|
|
||||||
# fullname in sys.modules, but we will end up with the same
|
|
||||||
# fake module name and that import will succeed since this
|
|
||||||
# one already has a temporary entry in the modules dict.
|
|
||||||
# Since this one "succeeded" temporarily that second
|
|
||||||
# invocation now will have created a fullname entry in
|
|
||||||
# sys.modules which we have to kill.
|
|
||||||
sys.modules.pop(fullname, None)
|
|
||||||
|
|
||||||
# If it's an important traceback we reraise it, otherwise
|
|
||||||
# we swallow it and try the next choice. The skipped frame
|
|
||||||
# is the one from __import__ above which we don't care about
|
|
||||||
if self.is_important_traceback(realname, tb):
|
|
||||||
reraise(exc_type, exc_value, tb.tb_next)
|
|
||||||
continue
|
|
||||||
module = sys.modules[fullname] = sys.modules[realname]
|
|
||||||
if '.' not in modname:
|
|
||||||
setattr(sys.modules[self.wrapper_module], modname, module)
|
|
||||||
|
|
||||||
if realname.startswith('flaskext.'):
|
|
||||||
warnings.warn(
|
|
||||||
"Detected extension named flaskext.{x}, please rename it "
|
|
||||||
"to flask_{x}. The old form is deprecated."
|
|
||||||
.format(x=modname), ExtDeprecationWarning
|
|
||||||
)
|
|
||||||
|
|
||||||
return module
|
|
||||||
raise ImportError('No module named %s' % fullname)
|
|
||||||
|
|
||||||
def is_important_traceback(self, important_module, tb):
|
|
||||||
"""Walks a traceback's frames and checks if any of the frames
|
|
||||||
originated in the given important module. If that is the case then we
|
|
||||||
were able to import the module itself but apparently something went
|
|
||||||
wrong when the module was imported. (Eg: import of an import failed).
|
|
||||||
"""
|
|
||||||
while tb is not None:
|
|
||||||
if self.is_important_frame(important_module, tb):
|
|
||||||
return True
|
|
||||||
tb = tb.tb_next
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_important_frame(self, important_module, tb):
|
|
||||||
"""Checks a single frame if it's important."""
|
|
||||||
g = tb.tb_frame.f_globals
|
|
||||||
if '__name__' not in g:
|
|
||||||
return False
|
|
||||||
|
|
||||||
module_name = g['__name__']
|
|
||||||
|
|
||||||
# Python 2.7 Behavior. Modules are cleaned up late so the
|
|
||||||
# name shows up properly here. Success!
|
|
||||||
if module_name == important_module:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Some python versions will clean up modules so early that the
|
|
||||||
# module name at that point is no longer set. Try guessing from
|
|
||||||
# the filename then.
|
|
||||||
filename = os.path.abspath(tb.tb_frame.f_code.co_filename)
|
|
||||||
test_string = os.path.sep + important_module.replace('.', os.path.sep)
|
|
||||||
return test_string + '.py' in filename or \
|
|
||||||
test_string + os.path.sep + '__init__.py' in filename
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
flaskext_compat
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Implements the ``flask.ext`` virtual package for versions of Flask
|
|
||||||
older than 0.7. This module is a noop if Flask 0.8 was detected.
|
|
||||||
|
|
||||||
Usage::
|
|
||||||
|
|
||||||
import flaskext_compat
|
|
||||||
flaskext_compat.activate()
|
|
||||||
from flask.ext import foo
|
|
||||||
|
|
||||||
:copyright: (c) 2015 by Armin Ronacher.
|
|
||||||
:license: BSD, see LICENSE for more details.
|
|
||||||
"""
|
|
||||||
import types
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class ExtensionImporter(object):
|
|
||||||
"""This importer redirects imports from this submodule to other locations.
|
|
||||||
This makes it possible to transition from the old flaskext.name to the
|
|
||||||
newer flask_name without people having a hard time.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module_choices, wrapper_module):
|
|
||||||
self.module_choices = module_choices
|
|
||||||
self.wrapper_module = wrapper_module
|
|
||||||
self.prefix = wrapper_module + '.'
|
|
||||||
self.prefix_cutoff = wrapper_module.count('.') + 1
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.__class__.__module__ == other.__class__.__module__ and \
|
|
||||||
self.__class__.__name__ == other.__class__.__name__ and \
|
|
||||||
self.wrapper_module == other.wrapper_module and \
|
|
||||||
self.module_choices == other.module_choices
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
return not self.__eq__(other)
|
|
||||||
|
|
||||||
def install(self):
|
|
||||||
sys.meta_path[:] = [x for x in sys.meta_path if self != x] + [self]
|
|
||||||
|
|
||||||
def find_module(self, fullname, path=None):
|
|
||||||
if fullname.startswith(self.prefix):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def load_module(self, fullname):
|
|
||||||
if fullname in sys.modules:
|
|
||||||
return sys.modules[fullname]
|
|
||||||
modname = fullname.split('.', self.prefix_cutoff)[self.prefix_cutoff]
|
|
||||||
for path in self.module_choices:
|
|
||||||
realname = path % modname
|
|
||||||
try:
|
|
||||||
__import__(realname)
|
|
||||||
except ImportError:
|
|
||||||
exc_type, exc_value, tb = sys.exc_info()
|
|
||||||
# since we only establish the entry in sys.modules at the
|
|
||||||
# end this seems to be redundant, but if recursive imports
|
|
||||||
# happen we will call into the move import a second time.
|
|
||||||
# On the second invocation we still don't have an entry for
|
|
||||||
# fullname in sys.modules, but we will end up with the same
|
|
||||||
# fake module name and that import will succeed since this
|
|
||||||
# one already has a temporary entry in the modules dict.
|
|
||||||
# Since this one "succeeded" temporarily that second
|
|
||||||
# invocation now will have created a fullname entry in
|
|
||||||
# sys.modules which we have to kill.
|
|
||||||
sys.modules.pop(fullname, None)
|
|
||||||
|
|
||||||
# If it's an important traceback we reraise it, otherwise
|
|
||||||
# we swallow it and try the next choice. The skipped frame
|
|
||||||
# is the one from __import__ above which we don't care about.
|
|
||||||
if self.is_important_traceback(realname, tb):
|
|
||||||
raise exc_type, exc_value, tb.tb_next
|
|
||||||
continue
|
|
||||||
module = sys.modules[fullname] = sys.modules[realname]
|
|
||||||
if '.' not in modname:
|
|
||||||
setattr(sys.modules[self.wrapper_module], modname, module)
|
|
||||||
return module
|
|
||||||
raise ImportError('No module named %s' % fullname)
|
|
||||||
|
|
||||||
def is_important_traceback(self, important_module, tb):
|
|
||||||
"""Walks a traceback's frames and checks if any of the frames
|
|
||||||
originated in the given important module. If that is the case then we
|
|
||||||
were able to import the module itself but apparently something went
|
|
||||||
wrong when the module was imported. (Eg: import of an import failed).
|
|
||||||
"""
|
|
||||||
while tb is not None:
|
|
||||||
if self.is_important_frame(important_module, tb):
|
|
||||||
return True
|
|
||||||
tb = tb.tb_next
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_important_frame(self, important_module, tb):
|
|
||||||
"""Checks a single frame if it's important."""
|
|
||||||
g = tb.tb_frame.f_globals
|
|
||||||
if '__name__' not in g:
|
|
||||||
return False
|
|
||||||
|
|
||||||
module_name = g['__name__']
|
|
||||||
|
|
||||||
# Python 2.7 Behavior. Modules are cleaned up late so the
|
|
||||||
# name shows up properly here. Success!
|
|
||||||
if module_name == important_module:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Some python versions will clean up modules so early that the
|
|
||||||
# module name at that point is no longer set. Try guessing from
|
|
||||||
# the filename then.
|
|
||||||
filename = os.path.abspath(tb.tb_frame.f_code.co_filename)
|
|
||||||
test_string = os.path.sep + important_module.replace('.', os.path.sep)
|
|
||||||
return test_string + '.py' in filename or \
|
|
||||||
test_string + os.path.sep + '__init__.py' in filename
|
|
||||||
|
|
||||||
|
|
||||||
def activate():
|
|
||||||
import flask
|
|
||||||
ext_module = types.ModuleType('flask.ext')
|
|
||||||
ext_module.__path__ = []
|
|
||||||
flask.ext = sys.modules['flask.ext'] = ext_module
|
|
||||||
importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], 'flask.ext')
|
|
||||||
importer.install()
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -64,7 +64,7 @@ setup(
|
||||||
description='A microframework based on Werkzeug, Jinja2 '
|
description='A microframework based on Werkzeug, Jinja2 '
|
||||||
'and good intentions',
|
'and good intentions',
|
||||||
long_description=__doc__,
|
long_description=__doc__,
|
||||||
packages=['flask', 'flask.ext', 'flask.json'],
|
packages=['flask', 'flask.json'],
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
platforms='any',
|
platforms='any',
|
||||||
|
|
|
||||||
|
|
@ -1,197 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
tests.ext
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Tests the extension import thing.
|
|
||||||
|
|
||||||
:copyright: (c) 2015 by Armin Ronacher.
|
|
||||||
:license: BSD, see LICENSE for more details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
try:
|
|
||||||
from imp import reload as reload_module
|
|
||||||
except ImportError:
|
|
||||||
reload_module = reload
|
|
||||||
|
|
||||||
from flask._compat import PY2
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def disable_extwarnings(recwarn):
|
|
||||||
from flask.exthook import ExtDeprecationWarning
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
assert set(w.category for w in recwarn.list) \
|
|
||||||
<= set([ExtDeprecationWarning])
|
|
||||||
recwarn.clear()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def importhook_setup(monkeypatch):
|
|
||||||
# we clear this out for various reasons. The most important one is
|
|
||||||
# that a real flaskext could be in there which would disable our
|
|
||||||
# fake package. Secondly we want to make sure that the flaskext
|
|
||||||
# import hook does not break on reloading.
|
|
||||||
for entry, value in list(sys.modules.items()):
|
|
||||||
if (
|
|
||||||
entry.startswith('flask.ext.') or
|
|
||||||
entry.startswith('flask_') or
|
|
||||||
entry.startswith('flaskext.') or
|
|
||||||
entry == 'flaskext'
|
|
||||||
) and value is not None:
|
|
||||||
monkeypatch.delitem(sys.modules, entry)
|
|
||||||
from flask import ext
|
|
||||||
reload_module(ext)
|
|
||||||
|
|
||||||
# reloading must not add more hooks
|
|
||||||
import_hooks = 0
|
|
||||||
for item in sys.meta_path:
|
|
||||||
cls = type(item)
|
|
||||||
if cls.__module__ == 'flask.exthook' and \
|
|
||||||
cls.__name__ == 'ExtensionImporter':
|
|
||||||
import_hooks += 1
|
|
||||||
assert import_hooks == 1
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
from flask import ext
|
|
||||||
for key in ext.__dict__:
|
|
||||||
assert '.' not in key
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def newext_simple(modules_tmpdir):
|
|
||||||
x = modules_tmpdir.join('flask_newext_simple.py')
|
|
||||||
x.write('ext_id = "newext_simple"')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def oldext_simple(modules_tmpdir):
|
|
||||||
flaskext = modules_tmpdir.mkdir('flaskext')
|
|
||||||
flaskext.join('__init__.py').write('\n')
|
|
||||||
flaskext.join('oldext_simple.py').write('ext_id = "oldext_simple"')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def newext_package(modules_tmpdir):
|
|
||||||
pkg = modules_tmpdir.mkdir('flask_newext_package')
|
|
||||||
pkg.join('__init__.py').write('ext_id = "newext_package"')
|
|
||||||
pkg.join('submodule.py').write('def test_function():\n return 42\n')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def oldext_package(modules_tmpdir):
|
|
||||||
flaskext = modules_tmpdir.mkdir('flaskext')
|
|
||||||
flaskext.join('__init__.py').write('\n')
|
|
||||||
oldext = flaskext.mkdir('oldext_package')
|
|
||||||
oldext.join('__init__.py').write('ext_id = "oldext_package"')
|
|
||||||
oldext.join('submodule.py').write('def test_function():\n'
|
|
||||||
' return 42')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def flaskext_broken(modules_tmpdir):
|
|
||||||
ext = modules_tmpdir.mkdir('flask_broken')
|
|
||||||
ext.join('b.py').write('\n')
|
|
||||||
ext.join('__init__.py').write('import flask.ext.broken.b\n'
|
|
||||||
'import missing_module')
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_new_simple_import_normal(newext_simple):
|
|
||||||
from flask.ext.newext_simple import ext_id
|
|
||||||
assert ext_id == 'newext_simple'
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_new_simple_import_module(newext_simple):
|
|
||||||
from flask.ext import newext_simple
|
|
||||||
assert newext_simple.ext_id == 'newext_simple'
|
|
||||||
assert newext_simple.__name__ == 'flask_newext_simple'
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_new_package_import_normal(newext_package):
|
|
||||||
from flask.ext.newext_package import ext_id
|
|
||||||
assert ext_id == 'newext_package'
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_new_package_import_module(newext_package):
|
|
||||||
from flask.ext import newext_package
|
|
||||||
assert newext_package.ext_id == 'newext_package'
|
|
||||||
assert newext_package.__name__ == 'flask_newext_package'
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_new_package_import_submodule_function(newext_package):
|
|
||||||
from flask.ext.newext_package.submodule import test_function
|
|
||||||
assert test_function() == 42
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_new_package_import_submodule(newext_package):
|
|
||||||
from flask.ext.newext_package import submodule
|
|
||||||
assert submodule.__name__ == 'flask_newext_package.submodule'
|
|
||||||
assert submodule.test_function() == 42
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_old_simple_import_normal(oldext_simple):
|
|
||||||
from flask.ext.oldext_simple import ext_id
|
|
||||||
assert ext_id == 'oldext_simple'
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_old_simple_import_module(oldext_simple):
|
|
||||||
from flask.ext import oldext_simple
|
|
||||||
assert oldext_simple.ext_id == 'oldext_simple'
|
|
||||||
assert oldext_simple.__name__ == 'flaskext.oldext_simple'
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_old_package_import_normal(oldext_package):
|
|
||||||
from flask.ext.oldext_package import ext_id
|
|
||||||
assert ext_id == 'oldext_package'
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_old_package_import_module(oldext_package):
|
|
||||||
from flask.ext import oldext_package
|
|
||||||
assert oldext_package.ext_id == 'oldext_package'
|
|
||||||
assert oldext_package.__name__ == 'flaskext.oldext_package'
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_old_package_import_submodule(oldext_package):
|
|
||||||
from flask.ext.oldext_package import submodule
|
|
||||||
assert submodule.__name__ == 'flaskext.oldext_package.submodule'
|
|
||||||
assert submodule.test_function() == 42
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_old_package_import_submodule_function(oldext_package):
|
|
||||||
from flask.ext.oldext_package.submodule import test_function
|
|
||||||
assert test_function() == 42
|
|
||||||
|
|
||||||
|
|
||||||
def test_flaskext_broken_package_no_module_caching(flaskext_broken):
|
|
||||||
for x in range(2):
|
|
||||||
with pytest.raises(ImportError):
|
|
||||||
import flask.ext.broken
|
|
||||||
|
|
||||||
|
|
||||||
def test_no_error_swallowing(flaskext_broken):
|
|
||||||
with pytest.raises(ImportError) as excinfo:
|
|
||||||
import flask.ext.broken
|
|
||||||
# python3.6 raises a subclass of ImportError: 'ModuleNotFoundError'
|
|
||||||
assert issubclass(excinfo.type, ImportError)
|
|
||||||
if PY2:
|
|
||||||
message = 'No module named missing_module'
|
|
||||||
else:
|
|
||||||
message = 'No module named \'missing_module\''
|
|
||||||
assert str(excinfo.value) == message
|
|
||||||
assert excinfo.tb.tb_frame.f_globals is globals()
|
|
||||||
|
|
||||||
# reraise() adds a second frame so we need to skip that one too.
|
|
||||||
# On PY3 we even have another one :(
|
|
||||||
next = excinfo.tb.tb_next.tb_next
|
|
||||||
if not PY2:
|
|
||||||
next = next.tb_next
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
assert os.path.join('flask_broken', '__init__.py') in \
|
|
||||||
next.tb_frame.f_code.co_filename
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue