88the built-in function __import__ in order to change the semantics of
99the import statement, until now it has been difficult to combine the
1010effect 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
1413This 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
1817One hooks class is defined (Hooks), which uses the interface provided
1918by standard modules os and os.path. It should be used as the base
2019class 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
2322module in a search path and to load it. It defines a method which
2423searches for a module in a single directory; by overriding this method
2524one can redefine the details of the search. If the directory is None,
@@ -31,7 +30,7 @@ class for other hooks classes.
3130uses a file system hooks class to interact with the file system. Both
3231use 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
3534module, as well as interfaces to reload and unload a module. It also
3635provides interfaces to install and uninstall itself instead of the
3736default __import__ and reload (and unload) functions.
@@ -49,26 +48,28 @@ class for other hooks classes.
4948by the way the __import__ hook is used by the Python interpreter.) It
5049would 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
5854import __builtin__
5955import imp
6056import os
6157import sys
58+ import string
59+
60+
61+ VERBOSE = 0
6262
6363
6464from 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
6970class _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
9094class 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
153147class 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+
361499default_importer = None
362500current_importer = None
363501
0 commit comments