Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9f5c36f

Browse files
committed
Support loading of packages. (I had this coded up for a while but
didn't want to commit until it had been tested. I presume that it works in Grail.)
1 parent be0b62c commit 9f5c36f

1 file changed

Lines changed: 172 additions & 34 deletions

File tree

Lib/ihooks.py

Lines changed: 172 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@
88
the built-in function __import__ in order to change the semantics of
99
the import statement, until now it has been difficult to combine the
1010
effect of different __import__ hacks, like loading modules from URLs
11-
(rimport.py), implementing a hierarchical module namespace (newimp.py)
12-
or restricted execution (rexec.py).
11+
by rimport.py, or restricted execution by rexec.py.
1312
1413
This module defines three new concepts:
1514
16-
(1) A "file system hooks" class provides an interface to a filesystem.
15+
1) A "file system hooks" class provides an interface to a filesystem.
1716
1817
One hooks class is defined (Hooks), which uses the interface provided
1918
by standard modules os and os.path. It should be used as the base
2019
class for other hooks classes.
2120
22-
(2) A "module loader" class provides an interface to to search for a
21+
2) A "module loader" class provides an interface to to search for a
2322
module in a search path and to load it. It defines a method which
2423
searches for a module in a single directory; by overriding this method
2524
one can redefine the details of the search. If the directory is None,
@@ -31,7 +30,7 @@ class for other hooks classes.
3130
uses a file system hooks class to interact with the file system. Both
3231
use the imp module's load_* interfaces to actually load the module.
3332
34-
(3) A "module importer" class provides an interface to import a
33+
3) A "module importer" class provides an interface to import a
3534
module, as well as interfaces to reload and unload a module. It also
3635
provides interfaces to install and uninstall itself instead of the
3736
default __import__ and reload (and unload) functions.
@@ -49,26 +48,28 @@ class for other hooks classes.
4948
by the way the __import__ hook is used by the Python interpreter.) It
5049
would also do wise to install a different version of reload().
5150
52-
XXX Should the imp.load_* functions also be called via the hooks
53-
instance?
54-
5551
"""
5652

5753

5854
import __builtin__
5955
import imp
6056
import os
6157
import sys
58+
import string
59+
60+
61+
VERBOSE = 0
6262

6363

6464
from imp import C_EXTENSION, PY_SOURCE, PY_COMPILED
65-
BUILTIN_MODULE = 32
66-
FROZEN_MODULE = 33
65+
from imp import C_BUILTIN, PY_FROZEN, PKG_DIRECTORY
66+
BUILTIN_MODULE = C_BUILTIN
67+
FROZEN_MODULE = PY_FROZEN
6768

6869

6970
class _Verbose:
7071

71-
def __init__(self, verbose = 0):
72+
def __init__(self, verbose = VERBOSE):
7273
self.verbose = verbose
7374

7475
def get_verbose(self):
@@ -84,7 +85,10 @@ def note(self, *args):
8485
apply(self.message, args)
8586

8687
def message(self, format, *args):
87-
print format%args
88+
if args:
89+
print format%args
90+
else:
91+
print format
8892

8993

9094
class BasicModuleLoader(_Verbose):
@@ -125,29 +129,19 @@ def find_module_in_dir(self, name, dir):
125129
return None
126130

127131
def find_builtin_module(self, name):
132+
# XXX frozen packages?
128133
if imp.is_builtin(name):
129134
return None, '', ('', '', BUILTIN_MODULE)
130135
if imp.is_frozen(name):
131136
return None, '', ('', '', FROZEN_MODULE)
132137
return None
133138

134139
def load_module(self, name, stuff):
135-
file, filename, (suff, mode, type) = stuff
140+
file, filename, info = stuff
136141
try:
137-
if type == BUILTIN_MODULE:
138-
return imp.init_builtin(name)
139-
if type == FROZEN_MODULE:
140-
return imp.init_frozen(name)
141-
if type == C_EXTENSION:
142-
return imp.load_dynamic(name, filename, file)
143-
if type == PY_SOURCE:
144-
return imp.load_source(name, filename, file)
145-
if type == PY_COMPILED:
146-
return imp.load_compiled(name, filename, file)
142+
return imp.load_module(name, file, filename, info)
147143
finally:
148144
if file: file.close()
149-
raise ImportError, "Unrecognized module type (%s) for %s" % \
150-
(`type`, name)
151145

152146

153147
class Hooks(_Verbose):
@@ -175,6 +169,8 @@ def load_compiled(self, name, filename, file=None):
175169
return imp.load_compiled(name, filename, file)
176170
def load_dynamic(self, name, filename, file=None):
177171
return imp.load_dynamic(name, filename, file)
172+
def load_package(self, name, filename, file=None):
173+
return imp.load_module(name, file, filename, ("", "", PKG_DIRECTORY))
178174

179175
def add_module(self, name):
180176
d = self.modules_dict()
@@ -214,7 +210,7 @@ class ModuleLoader(BasicModuleLoader):
214210
215211
"""
216212

217-
def __init__(self, hooks = None, verbose = 0):
213+
def __init__(self, hooks = None, verbose = VERBOSE):
218214
BasicModuleLoader.__init__(self, verbose)
219215
self.hooks = hooks or Hooks(verbose)
220216

@@ -231,15 +227,24 @@ def set_hooks(self, hooks):
231227
self.hooks = hooks
232228

233229
def find_builtin_module(self, name):
230+
# XXX frozen packages?
234231
if self.hooks.is_builtin(name):
235232
return None, '', ('', '', BUILTIN_MODULE)
236233
if self.hooks.is_frozen(name):
237234
return None, '', ('', '', FROZEN_MODULE)
238235
return None
239236

240-
def find_module_in_dir(self, name, dir):
237+
def find_module_in_dir(self, name, dir, allow_packages=1):
241238
if dir is None:
242239
return self.find_builtin_module(name)
240+
if allow_packages:
241+
fullname = self.hooks.path_join(dir, name)
242+
if self.hooks.path_isdir(fullname):
243+
stuff = self.find_module_in_dir("__init__", fullname, 0)
244+
if stuff:
245+
file = stuff[0]
246+
if file: file.close()
247+
return None, fullname, ('', '', PKG_DIRECTORY)
243248
for info in self.hooks.get_suffixes():
244249
suff, mode, type = info
245250
fullname = self.hooks.path_join(dir, name+suff)
@@ -251,7 +256,8 @@ def find_module_in_dir(self, name, dir):
251256
return None
252257

253258
def load_module(self, name, stuff):
254-
file, filename, (suff, mode, type) = stuff
259+
file, filename, info = stuff
260+
(suff, mode, type) = info
255261
try:
256262
if type == BUILTIN_MODULE:
257263
return self.hooks.init_builtin(name)
@@ -263,6 +269,8 @@ def load_module(self, name, stuff):
263269
m = self.hooks.load_source(name, filename, file)
264270
elif type == PY_COMPILED:
265271
m = self.hooks.load_compiled(name, filename, file)
272+
elif type == PKG_DIRECTORY:
273+
m = self.hooks.load_package(name, filename, file)
266274
else:
267275
raise ImportError, "Unrecognized module type (%s) for %s" % \
268276
(`type`, name)
@@ -278,6 +286,25 @@ class FancyModuleLoader(ModuleLoader):
278286

279287
def load_module(self, name, stuff):
280288
file, filename, (suff, mode, type) = stuff
289+
realfilename = filename
290+
path = None
291+
292+
if type == PKG_DIRECTORY:
293+
initstuff = self.find_module_in_dir("__init__", filename, 0)
294+
if not initstuff:
295+
raise ImportError, "No __init__ module in package %s" % name
296+
initfile, initfilename, initinfo = initstuff
297+
initsuff, initmode, inittype = initinfo
298+
if inittype not in (PY_COMPILED, PY_SOURCE):
299+
if initfile: initfile.close()
300+
raise ImportError, \
301+
"Bad type (%s) for __init__ module in package %s" % (
302+
`inittype`, name)
303+
path = [filename]
304+
file = initfile
305+
realfilename = initfilename
306+
type = inittype
307+
281308
if type == FROZEN_MODULE:
282309
code = self.hooks.get_frozen_object(name)
283310
elif type == PY_COMPILED:
@@ -286,25 +313,27 @@ def load_module(self, name, stuff):
286313
code = marshal.load(file)
287314
elif type == PY_SOURCE:
288315
data = file.read()
289-
code = compile(data, filename, 'exec')
316+
code = compile(data, realfilename, 'exec')
290317
else:
291318
return ModuleLoader.load_module(self, name, stuff)
319+
292320
m = self.hooks.add_module(name)
321+
if path:
322+
m.__path__ = path
293323
m.__file__ = filename
294324
exec code in m.__dict__
295325
return m
296326

297327

298-
class ModuleImporter(_Verbose):
328+
class BasicModuleImporter(_Verbose):
299329

300-
"""Default module importer; uses module loader.
330+
"""Basic module importer; uses module loader.
301331
302-
This provides the same functionality as built-in import, when
303-
combined with ModuleLoader.
332+
This provides basic import facilities but no package imports.
304333
305334
"""
306335

307-
def __init__(self, loader = None, verbose = 0):
336+
def __init__(self, loader = None, verbose = VERBOSE):
308337
_Verbose.__init__(self, verbose)
309338
self.loader = loader or ModuleLoader(None, verbose)
310339
self.modules = self.loader.modules_dict()
@@ -358,6 +387,115 @@ def uninstall(self):
358387
del __builtin__.unload
359388

360389

390+
class ModuleImporter(BasicModuleImporter):
391+
392+
"""A module importer that supports packages."""
393+
394+
def import_module(self, name, globals=None, locals=None, fromlist=None):
395+
parent = self.determine_parent(globals)
396+
q, tail = self.find_head_package(parent, name)
397+
m = self.load_tail(q, tail)
398+
if not fromlist:
399+
return q
400+
if hasattr(m, "__path__"):
401+
self.ensure_fromlist(m, fromlist)
402+
return m
403+
404+
def determine_parent(self, globals):
405+
if not globals or not globals.has_key("__name__"):
406+
return None
407+
pname = globals['__name__']
408+
if globals.has_key("__path__"):
409+
parent = self.modules[pname]
410+
assert globals is parent.__dict__
411+
return parent
412+
if '.' in pname:
413+
i = string.rfind(pname, '.')
414+
pname = pname[:i]
415+
parent = self.modules[pname]
416+
assert parent.__name__ == pname
417+
return parent
418+
return None
419+
420+
def find_head_package(self, parent, name):
421+
if '.' in name:
422+
i = string.find(name, '.')
423+
head = name[:i]
424+
tail = name[i+1:]
425+
else:
426+
head = name
427+
tail = ""
428+
if parent:
429+
qname = "%s.%s" % (parent.__name__, head)
430+
else:
431+
qname = head
432+
q = self.import_it(head, qname, parent)
433+
if q: return q, tail
434+
if parent:
435+
qname = head
436+
parent = None
437+
q = self.import_it(head, qname, parent)
438+
if q: return q, tail
439+
raise ImportError, "No module named " + qname
440+
441+
def load_tail(self, q, tail):
442+
m = q
443+
while tail:
444+
i = string.find(tail, '.')
445+
if i < 0: i = len(tail)
446+
head, tail = tail[:i], tail[i+1:]
447+
mname = "%s.%s" % (m.__name__, head)
448+
m = self.import_it(head, mname, m)
449+
if not m:
450+
raise ImportError, "No module named " + mname
451+
return m
452+
453+
def ensure_fromlist(self, m, fromlist, recursive=0):
454+
for sub in fromlist:
455+
if sub == "*":
456+
if not recursive:
457+
try:
458+
all = m.__all__
459+
except AttributeError:
460+
pass
461+
else:
462+
self.ensure_fromlist(m, all, 1)
463+
continue
464+
if sub != "*" and not hasattr(m, sub):
465+
subname = "%s.%s" % (m.__name__, sub)
466+
submod = self.import_it(sub, subname, m)
467+
if not submod:
468+
raise ImportError, "No module named " + subname
469+
470+
def import_it(self, partname, fqname, parent):
471+
if not partname:
472+
raise ValueError, "Empty module name"
473+
try:
474+
return self.modules[fqname]
475+
except KeyError:
476+
pass
477+
try:
478+
path = parent and parent.__path__
479+
except AttributeError:
480+
return None
481+
stuff = self.loader.find_module(partname, path)
482+
if not stuff:
483+
return None
484+
m = self.loader.load_module(fqname, stuff)
485+
if parent:
486+
setattr(parent, partname, m)
487+
return m
488+
489+
def reload(self, module):
490+
name = module.__name__
491+
if '.' not in name:
492+
return self.import_it(name, name, None)
493+
i = string.rfind(name, '.')
494+
pname = name[:i]
495+
parent = self.modules[pname]
496+
return self.import_it(name[i+1:], name, parent)
497+
498+
361499
default_importer = None
362500
current_importer = None
363501

0 commit comments

Comments
 (0)