Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 126 lines (105 sloc) 5.038 kB
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
1 # -*- coding: utf-8 -*-
2 """
3 flaskext_compat
4 ~~~~~~~~~~~~~~~
5
6 Implements the ``flask.ext`` virtual package for versions of Flask
7 older than 0.7. This module is a noop if Flask 0.8 was detected.
8
9 Usage::
10
11 import flaskext_compat
444698d @alekzvik Changed docstring according to docs.
alekzvik authored
12 flaskext_compat.activate()
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
13 from flask.ext import foo
14
33534bb @Parkayun Happy New Year 2015
Parkayun authored
15 :copyright: (c) 2015 by Armin Ronacher.
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
16 :license: BSD, see LICENSE for more details.
17 """
2de525c @Carreau importlib deprecated in 3.5.
Carreau authored
18 import types
7997bae @mitsuhiko Explicitly activate compat module
authored
19 import sys
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
20 import os
7997bae @mitsuhiko Explicitly activate compat module
authored
21
22
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
23 class ExtensionImporter(object):
24 """This importer redirects imports from this submodule to other locations.
25 This makes it possible to transition from the old flaskext.name to the
26 newer flask_name without people having a hard time.
27 """
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
28
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
29 def __init__(self, module_choices, wrapper_module):
30 self.module_choices = module_choices
31 self.wrapper_module = wrapper_module
32 self.prefix = wrapper_module + '.'
33 self.prefix_cutoff = wrapper_module.count('.') + 1
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
34
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
35 def __eq__(self, other):
36 return self.__class__.__module__ == other.__class__.__module__ and \
37 self.__class__.__name__ == other.__class__.__name__ and \
38 self.wrapper_module == other.wrapper_module and \
39 self.module_choices == other.module_choices
40
41 def __ne__(self, other):
42 return not self.__eq__(other)
43
44 def install(self):
45 sys.meta_path[:] = [x for x in sys.meta_path if self != x] + [self]
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
46
1e39871 @QuentinRoy Add back path=None argument into find_module. This fixes #618 and rev…
QuentinRoy authored
47 def find_module(self, fullname, path=None):
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
48 if fullname.startswith(self.prefix):
49 return self
50
51 def load_module(self, fullname):
7997bae @mitsuhiko Explicitly activate compat module
authored
52 if fullname in sys.modules:
53 return sys.modules[fullname]
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
54 modname = fullname.split('.', self.prefix_cutoff)[self.prefix_cutoff]
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
55 for path in self.module_choices:
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
56 realname = path % modname
57 try:
58 __import__(realname)
59 except ImportError:
9a70e62 @mitsuhiko No longer swallow important import errors.
authored
60 exc_type, exc_value, tb = sys.exc_info()
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
61 # since we only establish the entry in sys.modules at the
a2eb5ef @florentx few typos
florentx authored
62 # end this seems to be redundant, but if recursive imports
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
63 # happen we will call into the move import a second time.
64 # On the second invocation we still don't have an entry for
65 # fullname in sys.modules, but we will end up with the same
66 # fake module name and that import will succeed since this
67 # one already has a temporary entry in the modules dict.
68 # Since this one "succeeded" temporarily that second
69 # invocation now will have created a fullname entry in
70 # sys.modules which we have to kill.
9691b7f @mitsuhiko Deal with partially setup packages in the redirect hook.
authored
71 sys.modules.pop(fullname, None)
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
72
73 # If it's an important traceback we reraise it, otherwise
74 # we swallow it and try the next choice. The skipped frame
a2eb5ef @florentx few typos
florentx authored
75 # is the one from __import__ above which we don't care about.
9a70e62 @mitsuhiko No longer swallow important import errors.
authored
76 if self.is_important_traceback(realname, tb):
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
77 raise exc_type, exc_value, tb.tb_next
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
78 continue
7997bae @mitsuhiko Explicitly activate compat module
authored
79 module = sys.modules[fullname] = sys.modules[realname]
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
80 if '.' not in modname:
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
81 setattr(sys.modules[self.wrapper_module], modname, module)
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
82 return module
9a70e62 @mitsuhiko No longer swallow important import errors.
authored
83 raise ImportError('No module named %s' % fullname)
84
85 def is_important_traceback(self, important_module, tb):
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
86 """Walks a traceback's frames and checks if any of the frames
87 originated in the given important module. If that is the case then we
88 were able to import the module itself but apparently something went
89 wrong when the module was imported. (Eg: import of an import failed).
90 """
9a70e62 @mitsuhiko No longer swallow important import errors.
authored
91 while tb is not None:
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
92 if self.is_important_frame(important_module, tb):
9a70e62 @mitsuhiko No longer swallow important import errors.
authored
93 return True
94 tb = tb.tb_next
95 return False
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
96
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
97 def is_important_frame(self, important_module, tb):
98 """Checks a single frame if it's important."""
99 g = tb.tb_frame.f_globals
100 if '__name__' not in g:
101 return False
102
103 module_name = g['__name__']
104
105 # Python 2.7 Behavior. Modules are cleaned up late so the
106 # name shows up properly here. Success!
107 if module_name == important_module:
108 return True
109
a2eb5ef @florentx few typos
florentx authored
110 # Some python versions will clean up modules so early that the
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
111 # module name at that point is no longer set. Try guessing from
112 # the filename then.
113 filename = os.path.abspath(tb.tb_frame.f_code.co_filename)
114 test_string = os.path.sep + important_module.replace('.', os.path.sep)
115 return test_string + '.py' in filename or \
116 test_string + os.path.sep + '__init__.py' in filename
117
e944167 @mitsuhiko Added the flaskext_compat module to support flask.ext in 0.7 and earl…
authored
118
7997bae @mitsuhiko Explicitly activate compat module
authored
119 def activate():
120 import flask
2de525c @Carreau importlib deprecated in 3.5.
Carreau authored
121 ext_module = types.ModuleType('flask.ext')
95c4dcb @mitsuhiko Refactored flask.ext process to not swallow exceptions on weird Pythons.
authored
122 ext_module.__path__ = []
123 flask.ext = sys.modules['flask.ext'] = ext_module
124 importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], 'flask.ext')
125 importer.install()
Something went wrong with that request. Please try again.