|
Package Dropbox ::
Package web2py ::
Package gluon ::
Module custom_import
|
|
1
2
3
4 import __builtin__
5 import os
6 import re
7 import sys
8 import threading
9 import traceback
10 from gluon import current
11
12 NATIVE_IMPORTER = __builtin__.__import__
13 INVALID_MODULES = set(('', 'gluon', 'applications', 'custom_import'))
14
15
16
17
22
23
25 assert track in (True, False), "must be True or False"
26 current.request._custom_import_track_changes = track
27
28
31
32
35
36
37 -def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1):
38 """
39 The web2py custom importer. Like the standard Python importer but it
40 tries to transform import statements as something like
41 "import applications.app_name.modules.x".
42 If the import failed, fall back on naive_importer
43 """
44
45 globals = globals or {}
46 locals = locals or {}
47 fromlist = fromlist or []
48
49 try:
50 if current.request._custom_import_track_changes:
51 base_importer = TRACK_IMPORTER
52 else:
53 base_importer = NATIVE_IMPORTER
54 except:
55 base_importer = NATIVE_IMPORTER
56
57
58 if hasattr(current, 'request') \
59 and level <= 0 \
60 and not name.split('.')[0] in INVALID_MODULES \
61 and isinstance(globals, dict):
62 import_tb = None
63 try:
64 items = current.request.folder.split(os.path.sep)
65 if not items[-1]:
66 items = items[:-1]
67 modules_prefix = '.'.join(items[-2:]) + '.modules'
68 if not fromlist:
69
70 result = None
71 for itemname in name.split("."):
72 new_mod = base_importer(
73 modules_prefix, globals, locals, [itemname], level)
74 try:
75 result = result or new_mod.__dict__[itemname]
76 except KeyError, e:
77 raise ImportError, 'Cannot import module %s' % str(e)
78 modules_prefix += "." + itemname
79 return result
80 else:
81
82 pname = modules_prefix + "." + name
83 return base_importer(pname, globals, locals, fromlist, level)
84 except ImportError, e1:
85 import_tb = sys.exc_info()[2]
86 try:
87 return NATIVE_IMPORTER(name, globals, locals, fromlist, level)
88 except ImportError, e3:
89 raise ImportError, e1, import_tb
90 except Exception, e2:
91 raise e2
92 finally:
93 if import_tb:
94 import_tb = None
95
96 return NATIVE_IMPORTER(name, globals, locals, fromlist, level)
97
98
100 """
101 An importer tracking the date of the module files and reloading them when
102 they have changed.
103 """
104
105 THREAD_LOCAL = threading.local()
106 PACKAGE_PATH_SUFFIX = os.path.sep + "__init__.py"
107
109 self._import_dates = {}
110
111 - def __call__(self, name, globals=None, locals=None, fromlist=None, level=-1):
112 """
113 The import method itself.
114 """
115 globals = globals or {}
116 locals = locals or {}
117 fromlist = fromlist or []
118 if not hasattr(self.THREAD_LOCAL, '_modules_loaded'):
119 self.THREAD_LOCAL._modules_loaded = set()
120 try:
121
122 self._update_dates(name, globals, locals, fromlist, level)
123
124 result = NATIVE_IMPORTER(name, globals, locals, fromlist, level)
125
126 self._update_dates(name, globals, locals, fromlist, level)
127 return result
128 except Exception, e:
129 raise
130
131 - def _update_dates(self, name, globals, locals, fromlist, level):
132 """
133 Update all the dates associated to the statement import. A single
134 import statement may import many modules.
135 """
136
137 self._reload_check(name, globals, locals, level)
138 for fromlist_name in fromlist or []:
139 pname = "%s.%s" % (name, fromlist_name)
140 self._reload_check(pname, globals, locals, level)
141
143 """
144 Update the date associated to the module and reload the module if
145 the file has changed.
146 """
147 module = sys.modules.get(name)
148 file = self._get_module_file(module)
149 if file:
150 date = self._import_dates.get(file)
151 new_date = None
152 reload_mod = False
153 mod_to_pack = False
154 try:
155 new_date = os.path.getmtime(file)
156 except:
157 self._import_dates.pop(file, None)
158
159
160 if file.endswith(".py"):
161
162 file = os.path.splitext(file)[0]
163 reload_mod = os.path.isdir(file) \
164 and os.path.isfile(file + self.PACKAGE_PATH_SUFFIX)
165 mod_to_pack = reload_mod
166 else:
167 file += ".py"
168 reload_mod = os.path.isfile(file)
169 if reload_mod:
170 new_date = os.path.getmtime(file)
171 if reload_mod or not date or new_date > date:
172 self._import_dates[file] = new_date
173 if reload_mod or (date and new_date > date):
174 if module not in self.THREAD_LOCAL._modules_loaded:
175 if mod_to_pack:
176
177 mod_name = module.__name__
178 del sys.modules[mod_name]
179
180 NATIVE_IMPORTER(mod_name, globals, locals, [], level)
181 else:
182 reload(module)
183 self.THREAD_LOCAL._modules_loaded.add(module)
184
186 """
187 Get the absolute path file associated to the module or None.
188 """
189 file = getattr(module, "__file__", None)
190 if file:
191
192 file = os.path.splitext(file)[0] + ".py"
193 if file.endswith(self.PACKAGE_PATH_SUFFIX):
194 file = os.path.dirname(file)
195 return file
196
197 TRACK_IMPORTER = TrackImporter()
198