|
11 | 11 | import sys
|
12 | 12 | import types
|
13 | 13 |
|
| 14 | +import os.path |
| 15 | +import imp |
| 16 | +NoSource = Exception |
| 17 | +Loaded = {} |
| 18 | + |
| 19 | + |
14 | 20 | import six
|
15 | 21 | from six.moves import reprlib
|
16 | 22 |
|
@@ -1109,6 +1115,44 @@ def call_function(self, arg, args, kwargs):
|
1109 | 1115 | retval = func(*posargs, **namedargs)
|
1110 | 1116 | self.push(retval)
|
1111 | 1117 |
|
| 1118 | + def import_module(self, m, fromList, level): |
| 1119 | + f = self.frame |
| 1120 | + res = self.import_python_module(m, f.f_globals, f.f_locals, fromList, level) |
| 1121 | + self.push(res) |
| 1122 | + |
| 1123 | + def import_python_module(self, modulename, glo, loc, fromlist, level, search=None): |
| 1124 | + """Import a python module. |
| 1125 | + `modulename` is the name of the module, possibly a dot-separated name. |
| 1126 | + `fromlist` is the list of things to imported from the module. |
| 1127 | + """ |
| 1128 | + try: |
| 1129 | + if '.' not in modulename: |
| 1130 | + mymod = find_module(modulename, search, level, True, glo, loc) |
| 1131 | + # Open the source file. |
| 1132 | + try: |
| 1133 | + with open(mymod.__file__, "rU") as source_file: |
| 1134 | + source = source_file.read() |
| 1135 | + if not source or source[-1] != '\n': source += '\n' |
| 1136 | + code = compile(source, mymod.__file__, "exec") |
| 1137 | + # Execute the source file. |
| 1138 | + self.run_code(code, f_globals=mymod.__dict__, f_locals=mymod.__dict__) |
| 1139 | + # strip it with fromlist |
| 1140 | + # get the defined module |
| 1141 | + return mymod |
| 1142 | + except IOError as e: |
| 1143 | + raise NoSource("module does not live in a file: %r" % modulename) |
| 1144 | + else: |
| 1145 | + pkgn, name = modulename.rsplit('.', 1) |
| 1146 | + pkg = find_module(pkgn, search, level, False, glo, loc) |
| 1147 | + mod = self.import_python_module(name, glo, loc, fromlist, level, pkg.__file__) |
| 1148 | + # mod is an attribute of pkg |
| 1149 | + setattr(pkg, mod.__name__, mod) |
| 1150 | + return pkg |
| 1151 | + except NoSource as e: |
| 1152 | + m = __import__(modulename, glo, loc, fromlist, level) |
| 1153 | + Loaded[modulename] = m |
| 1154 | + return m |
| 1155 | + |
1112 | 1156 | def byte_RETURN_VALUE(self):
|
1113 | 1157 | self.return_value = self.pop()
|
1114 | 1158 | if self.frame.generator:
|
@@ -1145,10 +1189,7 @@ def byte_YIELD_FROM(self):
|
1145 | 1189 |
|
1146 | 1190 | def byte_IMPORT_NAME(self, name):
|
1147 | 1191 | level, fromlist = self.popn(2)
|
1148 |
| - frame = self.frame |
1149 |
| - self.push( |
1150 |
| - __import__(name, frame.f_globals, frame.f_locals, fromlist, level) |
1151 |
| - ) |
| 1192 | + self.import_module(name, fromlist, level) |
1152 | 1193 |
|
1153 | 1194 | def byte_IMPORT_STAR(self):
|
1154 | 1195 | # TODO: this doesn't use __all__ properly.
|
@@ -1232,3 +1273,51 @@ def calculate_metaclass(metaclass, bases):
|
1232 | 1273 | elif not issubclass(winner, t):
|
1233 | 1274 | raise TypeError("metaclass conflict", winner, t)
|
1234 | 1275 | return winner
|
| 1276 | + |
| 1277 | + |
| 1278 | + |
| 1279 | +def find_module_absolute(name, searchpath, isfile): |
| 1280 | + # search path should really be appeneded to a list of paths |
| 1281 | + # that the interpreter knows about. For now, we only look in '.' |
| 1282 | + myname = name if not searchpath else "%s/%s" % (searchpath, name) |
| 1283 | + if isfile: |
| 1284 | + fname = "%s.py" % myname |
| 1285 | + return os.path.abspath(fname) if os.path.isfile(fname) else None |
| 1286 | + else: |
| 1287 | + return os.path.abspath(myname) if os.path.isdir(myname) else None |
| 1288 | + |
| 1289 | +def find_module_relative(name, searchpath): return None |
| 1290 | + |
| 1291 | +def find_module(name, searchpath, level, isfile=True, glo=None, loc=None): |
| 1292 | + """ |
| 1293 | + `level` specifies whether to use absolute and/or relative. |
| 1294 | + The default is -1 which is both absolute and relative |
| 1295 | + 0 means only absolute and positive values indicate number |
| 1296 | + parent directories to search relative to the directory of module |
| 1297 | + calling `__import__` |
| 1298 | + """ |
| 1299 | + if name in Loaded: return Loaded[name] |
| 1300 | + |
| 1301 | + assert level <= 0 # we dont implement relative yet |
| 1302 | + path = None |
| 1303 | + if level == 0: |
| 1304 | + path = find_module_absolute(name, searchpath, isfile) |
| 1305 | + elif level > 0: |
| 1306 | + path = find_module_relative(name, searchpath, isfile) |
| 1307 | + else: |
| 1308 | + res = find_module_absolute(name, searchpath, isfile) |
| 1309 | + path = find_module_relative(name, searchpath, isfile) if not res \ |
| 1310 | + else res |
| 1311 | + |
| 1312 | + if not path: |
| 1313 | + v = imp.find_module(name, searchpath) |
| 1314 | + if v and v[1]: |
| 1315 | + path = v[1] |
| 1316 | + else: |
| 1317 | + raise NoSource("<%s> was not found" % name) |
| 1318 | + mymod = types.ModuleType(name) |
| 1319 | + mymod.__file__ = path |
| 1320 | + mymod.__builtins__ = glo['__builtins__'] |
| 1321 | + # mark the module as being loaded |
| 1322 | + Loaded[name] = mymod |
| 1323 | + return mymod |
0 commit comments