1 """Prototype of 'import' functionality enhanced to implement packages.
3 Why packages? Packages enable module nesting and sibling module
4 imports. 'Til now, the python module namespace was flat, which
5 means every module had to have a unique name, in order to not
6 conflict with names of other modules on the load path. Furthermore,
7 suites of modules could not be structurally affiliated with one
10 With packages, a suite of, eg, email-oriented modules can include a
11 module named 'mailbox', without conflicting with the, eg, 'mailbox'
12 module of a shared-memory suite - 'email.mailbox' vs
13 'shmem.mailbox'. Packages also enable modules within a suite to
14 load other modules within their package without having the package
15 name hard-coded. Similarly, package suites of modules can be loaded
16 as a unit, by loading the package that contains them.
18 Usage: once installed (newimp.install(); newimp.revert() to revert to
19 the prior __import__ routine), 'import ...' and 'from ... import ...'
22 - import modules from the search path, as before.
24 - import modules from within other directory "packages" on the search
25 path using a '.' dot-delimited nesting syntax. The nesting is fully
28 For example, 'import test.test_types' will import the test_types
29 module within the 'test' package. The calling environment would
30 then access the module as 'test.test_types', which is the name of
31 the fully-loaded 'test_types' module. It is found contained within
32 the stub (ie, only partially loaded) 'test' module, hence accessed as
35 - import siblings from modules within a package, using '__.' as a shorthand
36 prefix to refer to the parent package. This enables referential
37 transparency - package modules need not know their package name.
39 The '__' package references are actually names assigned within
40 modules, to refer to their containing package. This means that
41 variable references can be made to imported modules, or to variables
42 defined via 'import ... from', also using the '__.var' shorthand
43 notation. This establishes a proper equivalence between the import
44 reference '__.sibling' and the var reference '__.sibling'.
46 - import an entire package as a unit, by importing the package directory.
47 If there is a module named '__init__.py' in the package, it controls the
48 load. Otherwise, all the modules in the dir, including packages, are
49 inherently loaded into the package module's namespace.
51 For example, 'import test' will load the modules of the entire 'test'
52 package, at least until a test failure is encountered.
54 In a package, a module with the name '__init__' has a special role.
55 If present in a package directory, then it is loaded into the package
56 module, instead of loading the contents of the directory. This
57 enables the __init__ module to control the load, possibly loading
58 the entire directory deliberately (using 'import __', or even
59 'from __ import *', to load all the module contents directly into the
62 - perform any combination of the above - have a package that contains
65 Modules have a few new attributes in support of packages. As mentioned
66 above, '__' is a shorthand attribute denoting the modules' parent package,
67 also denoted in the module by '__package__'. Additionally, modules have
68 associated with them a '__pkgpath__', a path by which sibling modules are
71 __version__
= "$Revision$"
74 # Ken.Manheimer@nist.gov, 5-Apr-1995, for python 1.2
76 # Issues (scattered in code - search for three asterisks)
77 # *** Despite my efforts, 'reload(newimp)' will foul things up.
78 # *** Normalize_pathname will only work for Unix - which we need to detect.
79 # *** when a module with the name of the platform (as indicated by
80 # to-be-created var sys.platform), the package path gets '.' and the
82 # *** use sys.impadmin for things like an import load-hooks var
83 # *** Import-load-hook keying module name versus package path, which dictates
84 # additions to the default ('.' and os-specific dir) path
85 # *** Document that the __init__.py can set __.__pkgpath__, in which case that
86 # will be used for the package-relative loads.
87 # *** Add a 'recursive' option to reload, for reload of package constituent
88 # modules (including subpackages), as well. Or maybe that should be the
89 # default, and eg stub-completion should override that default. ???
93 # - 'sys.stub_modules' registers "incidental" (partially loaded) modules.
94 # A stub module is promoted to the fully-loaded 'sys.modules' list when it is
95 # explicitly loaded as a unit.
96 # - One load nuance - the actual load of most module types goes into the
97 # already-generated stub module. HOWEVER, eg dynamically loaded modules
98 # generate a new module object, which must supplant the existing stub. One
99 # consequence is that the import process must use indirection through
100 # sys.stub_modules or sys.modules to track the actual modules across some of
102 # - The test routines are cool, including a transient directory
103 # hierarchy facility, and a means of skipping to later tests by giving
104 # the test routine a numeric arg.
105 # - There may still be some loose ends, not to mention bugs. But the full
106 # functionality should be there.
107 # - The ImportStack object is necessary to carry the list of in-process imports
108 # across very open-ended recursions, where the state cannot be passed
109 # explicitly via the import_module calls; for a primary example, via exec of
110 # an 'import' statement within a module.
111 # - Python's (current) handling of extension modules, via imp.load_dynamic,
112 # does too much, some of which needs to be undone. See comments in
113 # load_module. Among other things, we actually change the __name__ of the
114 # module, which conceivably may break something.
119 VERBOSE
= 0 # Will be reset by init(1), also.
121 import sys
, string
, regex
, types
, os
, marshal
, traceback
122 import __main__
, __builtin__
124 newimp_globals
= vars()
127 import imp
# Build on this recent addition
129 raise ImportError, 'Pkg import module depends on optional "imp" module'#==X
131 from imp
import SEARCH_ERROR
, PY_SOURCE
, PY_COMPILED
, C_EXTENSION
133 def defvar(varNm
, envDict
, val
, override
=0):
134 """If VARNAME does not have value in DICT, assign VAL to it. Optional arg
135 OVERRIDE means force the assignment in any case."""
136 if (not envDict
.has_key(varNm
)) or override
:
139 def init(full_reset
=0):
140 """Do environment initialization, including retrofitting sys.modules with
141 module attributes."""
142 # Retrofit all existing modules with package attributes, under auspices of
145 locals, globals = vars(), newimp_globals
151 # sys.stub_modules tracks modules partially loaded modules, ie loaded only
152 # incidental to load of nested components. Together with sys.modules and
153 # the import stack, it serves as part of the module registration mechanism.
154 defvar('stub_modules', sys
.__dict
__, {}, full_reset
)
156 # Environment setup - "root" module, '__root__'
157 # Establish root package '__root__' in __main__ and newimp envs.
159 # Longhand for name of variable identifying module's containing package:
160 defvar('PKG_NM', globals, "__package__", full_reset
)
161 # Shorthand for module's container:
162 defvar('PKG_SHORT_NM', globals, "__", full_reset
)
163 defvar('PKG_SHORT_NM_LEN', globals, len(PKG_SHORT_NM
), full_reset
)
165 # Name of controlling module for a package, if any:
166 defvar('INIT_MOD_NM', globals, "__init__", full_reset
)
168 # Paths eventually will be extended to accomodate non-filesystem media -
169 # eg, URLs, composite objects, who knows.
171 # Name assigned in sys for general import administration:
172 defvar('IMP_SYS_NM', globals, "imp_admin", full_reset
)
173 defvar('MOD_LOAD_HOOKS', globals, "mod_load_hooks", full_reset
)
175 defvar(IMP_SYS_NM
, sys
.__dict
__, {MOD_LOAD_HOOKS
: {}}, full_reset
)
178 # Name assigned in each module to tuple describing module import attrs:
179 defvar('IMP_ADMIN', globals, "__impadmin__", full_reset
)
180 # The load-path obtaining for this package. Not defined for non-packages.
181 # If not set, package directory is used. If no package directory
182 # registered, sys.path is used.
183 defvar('PKG_PATH', globals, 0, full_reset
)
184 # File from which module was loaded - may be None, eg, for __root__:
185 defvar('MOD_TYPE', globals, 1, full_reset
)
186 # Exact path from which the module was loaded:
187 defvar('MOD_PATHNAME', globals, 2, full_reset
)
188 # Package within which the module was found:
189 defvar('MOD_PACKAGE', globals, 3, full_reset
)
190 defvar('USE_PATH', globals, 'either PKG_PATH or my dir', full_reset
)
192 # We're aliasing the top-level __main__ module as '__root__':
193 defvar('__root__', globals, __main__
, full_reset
)
194 defvar('ROOT_MOD_NM', globals, "__root__", full_reset
)
195 if not sys
.modules
.has_key('__root__') or full_reset
:
196 # and register it as an imported module:
197 sys
.modules
[ROOT_MOD_NM
] = __root__
199 # Register package information in all existing top-level modules - they'll
200 # the None's mean, among other things, that their USE_PATH's all defer to
202 for aMod
in sys
.modules
.values():
203 if (not aMod
.__dict
__.has_key(PKG_NM
)) or full_reset
:
204 set_mod_attrs(aMod
, None, __root__
, None, None)
207 __builtin__
.__import
__
208 defvar('origImportFunc', globals, __builtin__
.__import
__)
209 defvar('origReloadFunc', globals, __builtin__
.reload)
210 except AttributeError:
213 defvar('PY_PACKAGE', globals, 4, full_reset
)
214 defvar('PY_FROZEN', globals, 5, full_reset
)
215 defvar('PY_BUILTIN', globals, 6, full_reset
)
217 # Establish lookup table from mod-type "constants" to names:
218 defvar('mod_types', globals,
219 {SEARCH_ERROR
: 'SEARCH_ERROR',
220 PY_SOURCE
: 'PY_SOURCE',
221 PY_COMPILED
: 'PY_COMPILED',
222 C_EXTENSION
: 'C_EXTENSION',
223 PY_PACKAGE
: 'PY_PACKAGE',
224 PY_FROZEN
: 'PY_FROZEN',
225 PY_BUILTIN
: 'PY_BUILTIN'},
228 defvar('stack', globals, ImportStack(), full_reset
)
231 """Install newimp import_module() routine, for package support.
233 newimp.revert() reverts to __import__ routine that was superceded."""
234 __builtin__
.__import
__ = import_module
235 __builtin__
.reload = reload
236 __builtin__
.unload
= unload
237 __builtin__
.bypass
= bypass
238 return 'Enhanced import functionality in place.'
240 """Revert to original __builtin__.__import__ func, if newimp.install() has
242 if not (origImportFunc
and origReloadFunc
):
243 raise SystemError, "Can't find original import and reload funcs." # ==X
244 __builtin__
.__import
__ = origImportFunc
245 __builtin__
.reload = origReloadFunc
246 del __builtin__
.unload
, __builtin__
.bypass
247 return 'Original import routines back in place.'
249 def import_module(name
,
250 envLocals
=None, envGlobals
=None,
253 """Primary service routine implementing 'import' with package nesting.
255 NAME: name as specified to 'import NAME' or 'from NAME...'
256 LOCALS, GLOBALS: local and global dicts obtaining for import
257 FROMS: list of strings of "..." in 'import blat from ...'
258 INPKG: package to which the name search is restricted, for use
259 by recursive package loads (from import_module()).
261 A subtle difference from the old import - modules that do fail
262 initialization will not be registered in sys.modules, ie will not, in
263 effect, be registered as being loaded. Note further that packages which
264 fail their overall load, but have successfully loaded constituent modules,
265 will be accessible in the importing namespace as stub modules.
267 A new routine, 'newimp.bypass()', provides the means to circumvent
268 constituent modules that fail their load, in order to enable load of the
269 remainder of a package."""
271 rootMod
= sys
.modules
[ROOT_MOD_NM
]
273 note("import_module: seeking '%s'" % name
, 1)
275 # We need callers environment dict for local path and resulting module
278 # This should not happen, but does for imports called from within
280 envLocals
, envGlobals
= exterior()
284 elif envGlobals
.has_key(PKG_NM
):
285 pkg
= envGlobals
[PKG_NM
]
287 # ** KLUDGE - cover for modules that lack package attributes:
291 note(' - relative to package %s' % pkg
)
293 modList
= theMod
= absNm
= nesting
= None
296 # - absNm is absolute w.r.t. __root__
297 # - relNm is relative w.r.t. pkg.
299 absNm
, relNm
= pkg
.__name
__ + '.' + name
, name
301 absNm
, relNm
, pkg
= normalize_import_ref(name
, pkg
)
302 note("Normalized: %s%s" % (absNm
, (((relNm
!= absNm
)
303 and (" ('%s' in %s)" % (relNm
, pkg
)))
306 pkgPath
= get_mod_attrs(pkg
, USE_PATH
)
308 try: # try...finally guards import stack integrity.
310 if stack
.push(absNm
):
311 # We're nested inside a containing import of this module, perhaps
312 # indirectly. Avoid infinite recursion at this point by using the
313 # existing stub module, for now. Load of it will be completed by
314 # the superior import.
315 note('recursion on in-process module %s, punting with stub' %
317 theMod
= stack
.mod(absNm
)
321 # Try to find already-imported:
322 if sys
.modules
.has_key(absNm
):
323 note('found ' + absNm
+ ' already imported')
324 theMod
= sys
.modules
[absNm
]
325 stack
.mod(absNm
, theMod
)
327 else: # Actually do load, of one sort or another:
329 # Seek builtin or frozen first:
330 theMod
= imp
.init_builtin(absNm
)
332 set_mod_attrs(theMod
, None, pkg
, None, PY_BUILTIN
)
333 stack
.mod(absNm
, theMod
)
334 note('found builtin ' + absNm
)
336 theMod
= imp
.init_frozen(absNm
)
338 set_mod_attrs(theMod
, None, pkg
, None, PY_FROZEN
)
339 stack
.mod(absNm
, theMod
)
340 note('found frozen ' + absNm
)
343 # Not already-loaded, in-process, builtin, or frozen -
344 # we're seeking in the outside world (filesystem):
346 if sys
.stub_modules
.has_key(absNm
):
348 # A package for which we have a stub:
349 theMod
= reload(sys
.stub_modules
[absNm
], inPkg
)
353 # Now we actually search the fs.
355 if type(pkgPath
) == types
.StringType
:
358 # Find a path leading to the module:
359 modList
= find_module(relNm
, pkgPath
, absNm
)
361 raise ImportError, ("module '%s' not found" % #==X
364 # We have a list of successively nested dirs leading
365 # to the module, register with import admin, as stubs:
366 nesting
= register_mod_nesting(modList
, pkg
)
368 # Load from file if necessary and possible:
369 modNm
, modf
, path
, ty
= modList
[-1]
370 note('found type %s - %s' % (mod_types
[ty
[2]], absNm
))
372 # Establish the module object in question:
373 theMod
= procure_module(absNm
)
374 stack
.mod(absNm
, theMod
)
377 theMod
= load_module(theMod
, ty
[2], modf
, inPkg
)
379 commit_mod_containment(absNm
)
381 # Successful load - promote to fully-imported status:
382 register_module(theMod
, theMod
.__name
__)
385 # We have a loaded module (perhaps stub): situate specified components,
386 # and return appropriate thing. According to guido:
388 # "Note that for "from spam.ham import bacon" your function should
389 # return the object denoted by 'spam.ham', while for "import
390 # spam.ham" it should return the object denoted by 'spam' -- the
391 # STORE instructions following the import statement expect it this
393 # *** The above rationale should probably be reexamined, since newimp
394 # actually takes care of populating the caller's namespace.
398 # Return the outermost container, possibly stub:
400 return find_mod_registration(nesting
[0][0])
402 return find_mod_registration(string
.splitfields(absNm
,'.')[0])
407 finally: # Decrement stack registration:
411 def reload(module
, inPkg
= None):
412 """Re-parse and re-initialize an already (or partially) imported MODULE.
414 The argument can be an already loaded module object or a string name of a
415 loaded module or a "stub" module that was partially loaded package module
416 incidental to the full load of a contained module.
418 This is useful if you have edited the module source file using an external
419 editor and want to try out the new version without leaving the Python
420 interpreter. The return value is the resulting module object.
422 Contrary to the old 'reload', the load is sought from the same location
423 where the module was originally found. If you wish to do a fresh load from
424 a different module on the path, do an 'unload()' and then an import.
426 When a module is reloaded, its dictionary (containing the module's
427 global variables) is retained. Redefinitions of names will
428 override the old definitions, so this is generally not a problem.
429 If the new version of a module does not define a name that was
430 defined by the old version, the old definition remains. This
431 feature can be used to the module's advantage if it maintains a
432 global table or cache of objects -- with a `try' statement it can
433 test for the table's presence and skip its initialization if
436 It is legal though generally not very useful to reload built-in or
437 dynamically loaded modules, except for `sys', `__main__' and
438 `__builtin__'. In certain cases, however, extension modules are
439 not designed to be initialized more than once, and may fail in
440 arbitrary ways when reloaded.
442 If a module imports objects from another module using `from' ...
443 `import' ..., calling `reload()' for the other module does not
444 redefine the objects imported from it -- one way around this is to
445 re-execute the `from' statement, another is to use `import' and
446 qualified names (MODULE.NAME) instead.
448 If a module instantiates instances of a class, reloading the module
449 that defines the class does not affect the method definitions of
450 the instances, unless they are reinstantiated -- they continue to use the
451 old class definition. The same is true for derived classes."""
453 if type(module
) == types
.StringType
:
454 theMod
= find_mod_registration(module
)
455 elif type(module
) == types
.ModuleType
:
458 raise ImportError, '%s not already imported' # ==X
460 if theMod
in [sys
.modules
[ROOT_MOD_NM
], sys
.modules
['__builtin__']]:
461 raise ImportError, 'cannot re-init internal module' # ==X
464 thePath
= get_mod_attrs(theMod
, MOD_PATHNAME
)
469 # If we have no path for the module, we can only reload it from
471 note('no pathname registered for %s, doing full reload' % theMod
)
473 envGlobals
, envLocals
= exterior()
474 return import_module(theMod
.__name
__,
475 envGlobals
, envLocals
, None, inPkg
)
478 stack
.mod(theMod
.__name
__, theMod
)
479 ty
= get_mod_attrs(theMod
, MOD_TYPE
)
480 if ty
in [PY_SOURCE
, PY_COMPILED
]:
481 note('reload invoked for %s %s' % (mod_types
[ty
], theMod
))
482 thePath
, ty
, openFile
= prefer_compiled(thePath
, ty
)
484 openFile
= open(thePath
, get_suffixes(ty
)[1])
485 return load_module(theMod
, # ==>
490 """Remove registration for a module, so import will do a fresh load.
492 Returns the module registries (sys.modules and/or sys.stub_modules) where
494 if type(module
) == types
.ModuleType
:
495 module
= module
.__name
__
497 for which
in ['sys.modules', 'sys.stub_modules']:
505 raise ValueError, '%s not a module or a stub' % module
# ==X
508 """Register MODULE-NAME so module will be skipped, eg in package load."""
509 if sys
.modules
.has_key(modNm
):
510 raise ImportError("'%s' already imported, cannot be bypassed." % modNm
)
512 sys
.modules
[modNm
] = imp
.new_module('bypass()ed module %s' % modNm
)
513 commit_mod_containment(modNm
)
516 def normalize_import_ref(name
, pkg
):
517 """Produce absolute and relative nm and relative pkg given MODNM and origin
518 PACKAGE, reducing out all '__'s in the process."""
520 # First reduce out all the '__' container-refs we can:
521 outwards
, inwards
= 0, []
522 for nm
in string
.splitfields(name
, '.'):
523 if nm
== PKG_SHORT_NM
:
525 # Pop a containing inwards:
528 # (Effectively) leading '__' - notch outwards:
529 outwards
= outwards
+ 1
532 inwards
= string
.joinfields(inwards
, '.')
534 # Now identify the components:
537 pkg
= sys
.modules
[ROOT_MOD_NM
]
540 pkg
= pkg
.__dict
__[PKG_NM
] # We'll just loop at top
543 outwards
= outwards
- 1
545 if not inwards
: # Entire package:
546 return pkg
.__name
__, pkg
.__name
__, pkg
# ==>
547 else: # Name relative to package:
549 return inwards
, inwards
, pkg
# ==>
551 return pkg
.__name
__ + '.' + inwards
, inwards
, pkg
# ==>
554 """Provide judicious support for mutually recursive import loops.
556 Mutually recursive imports, eg a module that imports the package that
557 contains it, which in turn imports the module, are not uncommon, and must
558 be supported judiciously. This class is used to track cycles, so a module
559 already in the process of being imported (via 'stack.push(module)', and
560 concluded via 'stack.release(module)') is not redundantly pursued; *except*
561 when a module master '__init__.py' loads the module, in which case it is
562 'stack.relax(module)'ed, so the full import is pursued."""
568 def in_process(self
, modNm
):
569 """1 if modNm load already in process, 0 otherwise."""
570 return self
._cycles
.has_key(modNm
) # ==>
571 def looped(self
, modNm
):
572 """1 if modNm load has looped once or more, 0 otherwise."""
573 return modNm
in self
._looped
574 def push(self
, modNm
):
575 """1 if modNm already in process and not 'relax'ed, 0 otherwise.
576 (Note that the 'looped' status remains even when the cycle count
577 returns to 1. This is so error messages can indicate that it was, at
578 some point, looped during the import process.)"""
579 if self
.in_process(modNm
):
580 self
._looped
.append(modNm
)
581 self
._cycles
[modNm
] = self
._cycles
[modNm
] + 1
584 self
._cycles
[modNm
] = 1
586 def mod(self
, modNm
, mod
=None):
587 """Associate MOD-NAME with MODULE, for easy reference."""
589 self
._mods
[modNm
] = mod
592 return self
._mods
[modNm
] # ==>
595 def pop(self
, modNm
):
596 """Decrement stack count of MODNM"""
597 if self
.in_process(modNm
):
598 amt
= self
._cycles
[modNm
] = self
._cycles
[modNm
] - 1
600 del self
._cycles
[modNm
]
601 if modNm
in self
._looped
:
602 self
._looped
.remove(modNm
)
603 if self
._mods
.has_key(modNm
):
604 del self
._mods
[modNm
]
605 def relax(self
, modNm
):
606 """Enable modNm load despite being registered as already in-process."""
607 if self
._cycles
.has_key(modNm
):
608 del self
._cycles
[modNm
]
610 def find_module(name
, path
, absNm
=''):
611 """Locate module NAME on PATH. PATH is pathname string or a list of them.
613 Note that up-to-date compiled versions of a module are preferred to plain
614 source, and compilation is automatically performed when necessary and
617 Returns a list of the tuples returned by 'find_mod_file()', one for
618 each nested level, deepest last."""
620 checked
= [] # For avoiding redundant dir lists.
622 if not absNm
: absNm
= name
624 # Parse name into list of nested components,
625 expNm
= string
.splitfields(name
, '.')
629 if (type(curPath
) != types
.StringType
) or (curPath
in checked
):
630 # Disregard bogus or already investigated path elements:
633 # Register it for subsequent disregard.
634 checked
.append(curPath
)
638 # Non-nested module name:
640 got
= find_mod_file(curPath
, absNm
)
642 note('using %s' % got
[2], 3)
647 # Composite name specifying nested module:
649 gotList
= []; nameAccume
= expNm
[0]
651 got
= find_mod_file(curPath
, nameAccume
)
652 if not got
: # Continue to next prospective path.
656 nm
, file, fullPath
, ty
= got
658 # Work on successively nested components:
659 for component
in expNm
[1:]:
660 # 'ty'pe of containing component must be package:
661 if ty
[2] != PY_PACKAGE
:
662 gotList
, got
= [], None
665 nameAccume
= nameAccume
+ '.' + component
667 nameAccume
= component
668 got
= find_mod_file(fullPath
, nameAccume
)
671 nm
, file, fullPath
, ty
= got
674 gotList
, got
, nameAccume
= [], None, ''
676 # Found nesting all the way to the specified tip:
683 def find_mod_file(pathNm
, modname
):
684 """Find right module file given DIR and module NAME, compiling if needed.
686 If successful, returns quadruple consisting of:
689 - full pathname for the found file,
690 - a description triple as contained in the list returned by get_suffixes.
692 Otherwise, returns None.
694 Note that up-to-date compiled versions of a module are preferred to plain
695 source, and compilation is automatically performed, when necessary and
698 relNm
= modname
[1 + string
.rfind(modname
, '.'):]
700 for suff
, mode
, ty
in get_suffixes():
701 fullPath
= os
.path
.join(pathNm
, relNm
+ suff
)
702 note('trying ' + fullPath
+ '...', 4)
704 modf
= open(fullPath
, mode
)
706 # ** ?? Skip unreadable ones:
710 # Enforce directory characteristic:
711 if not os
.path
.isdir(fullPath
):
712 note('Skipping non-dir match ' + fullPath
, 3)
715 return (modname
, modf
, fullPath
, (suff
, mode
, ty
)) # ==>
718 elif ty
in [PY_SOURCE
, PY_COMPILED
]:
719 usePath
, useTy
, openFile
= prefer_compiled(fullPath
, ty
)
720 return (modname
, # ==>
725 elif ty
== C_EXTENSION
:
726 note('found C_EXTENSION ' + fullPath
, 3)
727 return (modname
, modf
, fullPath
, (suff
, mode
, ty
)) # ==>
730 raise SystemError, 'Unanticipated module type encountered' # ==X
734 def prefer_compiled(path
, ty
, modf
=None):
735 """Given a path to a .py or .pyc file, attempt to return a path to a
736 current pyc file, compiling the .py in the process if necessary. Returns
737 the path to the most current version we can get."""
742 modf
= open(path
, 'r')
745 note('working from PY_SOURCE', 3)
746 # Try for a compiled version:
747 pyc
= path
+ 'c' # Sadly, we're presuming '.py' suff.
748 if (not os
.path
.exists(pyc
) or
749 (os
.stat(path
)[8] > os
.stat(pyc
)[8])):
751 pyc
= compile_source(path
, modf
)
752 if pyc
and not (os
.stat(path
)[8] > os
.stat(pyc
)[8]):
753 # Either pyc was already newer or we just made it so; in either
754 # case it's what we crave:
755 note('but got newer compiled, ' + pyc
, 3)
757 return (pyc
, PY_COMPILED
, open(pyc
, 'rb')) # ==>
760 return (path
, PY_SOURCE
, modf
) # ==>
762 raise ImportError, 'Failed acces to .py and .pyc' # ==X
764 note("couldn't get newer compiled, using PY_SOURCE", 3)
766 return (path
, PY_SOURCE
, modf
) # ==>
768 raise ImportError, 'Failed acces to .py and .pyc' # ==X
770 elif ty
== PY_COMPILED
:
771 note('working from PY_COMPILED', 3)
774 modf
= open(path
, 'rb')
776 return prefer_compiled(path
[:-1], PY_SOURCE
)
777 # Make sure it is current, trying to compile if necessary, and
778 # prefer source failing that:
779 note('found compiled ' + path
, 3)
780 py
= path
[:-1] # ** Presuming '.pyc' suffix
781 if not os
.path
.exists(py
):
782 note('pyc SANS py: ' + path
, 3)
783 return (path
, PY_COMPILED
, open(py
, 'r')) # ==>
784 elif (os
.stat(py
)[8] > os
.stat(path
)[8]):
785 note('Forced to compile: ' + py
, 3)
786 pyc
= compile_source(py
, open(py
, 'r'))
788 return (pyc
, PY_COMPILED
, modf
) # ==>
790 note('failed compile - must use more recent .py', 3)
791 return (py
, PY_SOURCE
, open(py
, 'r')) # ==>
793 return (path
, PY_COMPILED
, modf
) # ==>
795 def load_module(theMod
, ty
, theFile
, fromMod
):
796 """Load module NAME, of TYPE, from FILE, within MODULE.
798 Optional arg fromMod indicates the module from which the load is being done
799 - necessary for detecting import of __ from a package's __init__ module.
801 Return the populated module object."""
803 # Note: we mint and register intermediate package directories, as necessary
805 name
= theMod
.__name
__
806 nameTail
= name
[1 + string
.rfind(name
, '.'):]
807 thePath
= theFile
.name
810 exec_into(theFile
, theMod
, theFile
.name
)
812 elif ty
== PY_COMPILED
:
813 pyc
= open(theFile
.name
, 'rb').read()
814 if pyc
[0:4] != imp
.get_magic():
815 raise ImportError, 'bad magic number: ' + theFile
.name
# ==X
816 code
= marshal
.loads(pyc
[8:])
817 exec_into(code
, theMod
, theFile
.name
)
819 elif ty
== C_EXTENSION
:
820 # Dynamically loaded C_EXTENSION modules do too much import admin,
821 # themselves, which we need to *undo* in order to integrate them with
822 # the new import scheme.
823 # 1 They register themselves in sys.modules, registering themselves
824 # under their top-level names. Have to rectify that.
825 # 2 The produce their own module objects, *unless* they find an
826 # existing module already registered a la 1, above. We employ this
827 # quirk to make it use the already generated module.
829 # Stash a ref to any module that is already registered under the
830 # dyamic module's simple name (nameTail), so we can reestablish it
831 # after the dynamic takes over its' slot:
834 if sys
.modules
.has_key(nameTail
):
835 protMod
= sys
.modules
[nameTail
]
836 # Trick the dynamic load, by registering the module we generated
837 # under the nameTail of the module we're loading, so the one we're
838 # loading will use that established module, rather than producing a
840 sys
.modules
[nameTail
] = theMod
841 theMod
= imp
.load_dynamic(nameTail
, thePath
, theFile
)
842 theMod
.__name
__ = name
843 # Cleanup dynamic mod's bogus self-registration, if necessary:
846 # ... reinstating the one that was already there...
847 sys
.modules
[nameTail
] = protMod
849 if sys
.modules
.has_key(nameTail
):
850 # Certain, as long os dynamics continue to misbehave.
851 del sys
.modules
[nameTail
]
852 stack
.mod(name
, theMod
)
853 if sys
.stub_modules
.has_key(name
):
854 sys
.stub_modules
[name
] = theMod
855 elif sys
.modules
.has_key(name
):
856 sys
.modules
[name
] = theMod
858 # Provide import-nesting info, including signs of circularity:
859 raise sys
.exc_type
, import_trail_msg(str(sys
.exc_value
),# ==X
862 elif ty
== PY_PACKAGE
:
863 # Load package constituents, doing the controlling module *if* it
864 # exists *and* it isn't already in process:
866 init_mod_f
= init_mod
= None
867 if not stack
.in_process(name
+ '.' + INIT_MOD_NM
):
868 # Not already doing __init__ - check for it:
869 init_mod_f
= find_mod_file(thePath
, INIT_MOD_NM
)
871 note('skipping already-in-process %s.%s' % (theMod
.__name
__,
875 note("Found package's __init__: " + init_mod_f
[2])
876 # Enable full continuance of containing-package-load from __init__:
877 if stack
.in_process(theMod
.__name
__):
878 stack
.relax(theMod
.__name
__)
879 init_mod
= import_module(INIT_MOD_NM
,
880 theMod
.__dict
__, theMod
.__dict
__,
884 # ... or else recursively load all constituent modules, except
886 for prospect
in mod_prospects(thePath
):
887 if prospect
!= INIT_MOD_NM
:
888 import_module(prospect
,
889 theMod
.__dict
__, theMod
.__dict
__,
894 raise ImportError, 'Unimplemented import type: %s' % ty
# ==X
898 def exec_into(obj
, module
, path
):
899 """Helper for load_module, execfile/exec path or code OBJ within MODULE."""
901 # This depends on ability of exec and execfile to mutilate, erhm, mutate
902 # the __dict__ of a module. It will not work if/when this becomes
903 # disallowed, as it is for normal assignments.
906 if type(obj
) == types
.FileType
:
907 execfile(path
, module
.__dict
__, module
.__dict
__)
908 elif type(obj
) in [types
.CodeType
, types
.StringType
]:
909 exec obj
in module
.__dict
__, module
.__dict
__
911 # Make the error message nicer?
912 raise sys
.exc_type
, import_trail_msg(str(sys
.exc_value
), # ==X
917 def mod_prospects(path
):
918 """Return a list of prospective modules within directory PATH.
920 We actually return the distinct names resulting from stripping the dir
921 entries (excluding os.curdir and os.pardir) of their suffixes (as
922 represented by 'get_suffixes').
924 (Note that matches for the PY_PACKAGE type with null suffix are
925 implicitly constrained to be directories.)"""
927 # We actually strip the longest matching suffixes, so eg 'dbmmodule.so'
928 # mates with 'module.so' rather than '.so'.
930 dirList
= os
.listdir(path
)
931 excludes
= [os
.curdir
, os
.pardir
]
932 sortedSuffs
= sorted_suffixes()
935 if item
in excludes
: continue # ==^
936 for suff
in sortedSuffs
:
937 # *** ?? maybe platform-specific:
940 if os
.path
.isdir(os
.path
.join(path
, item
)):
942 elif item
[sub
:] == suff
:
944 if not it
in entries
:
951 def procure_module(name
):
952 """Return an established or else new module object having NAME.
954 First checks sys.modules, then sys.stub_modules."""
956 if sys
.modules
.has_key(name
):
957 return sys
.modules
[name
] # ==>
958 elif sys
.stub_modules
.has_key(name
):
959 return sys
.stub_modules
[name
] # ==>
961 return (stack
.mod(name
) or imp
.new_module(name
)) # ==>
963 def commit_mod_containment(name
):
964 """Bind a module object and its containers within their respective
966 cume
, pkg
= '', find_mod_registration(ROOT_MOD_NM
)
967 for next
in string
.splitfields(name
, '.'):
969 cume
= cume
+ '.' + next
972 cumeMod
= find_mod_registration(cume
)
973 pkg
.__dict
__[next
] = cumeMod
976 def register_mod_nesting(modList
, pkg
):
977 """Given find_module()-style NEST-LIST and parent PACKAGE, register new
978 package components as stub modules, and return list of nested
979 module/relative-name pairs.
981 Note that the modules objects are not situated in their containing packages
982 here - that is left 'til after a successful load, and done by
983 commit_mod_nesting()."""
986 for modNm
, modF
, path
, ty
in modList
:
988 relNm
= modNm
[1 + string
.rfind(modNm
, '.'):]
990 if sys
.modules
.has_key(modNm
):
991 theMod
= sys
.modules
[modNm
] # Nestle in containing package
992 pkg
= theMod
# Set as parent for next in sequence.
993 elif sys
.stub_modules
.has_key(modNm
):
994 # Similar to above...
995 theMod
= sys
.stub_modules
[modNm
]
998 theMod
= procure_module(modNm
)
999 stack
.mod(modNm
, theMod
)
1000 # *** ??? Should we be using 'path' instead of modF.name? If not,
1001 # should we get rid of the 'path' return val?
1002 set_mod_attrs(theMod
, normalize_pathname(modF
.name
),
1004 if ty
[2] == PY_PACKAGE
:
1005 # Register as a stub:
1006 register_module(theMod
, modNm
, 1)
1008 nesting
.append((theMod
.__name
__,relNm
))
1012 def register_module(theMod
, name
, stub
=0):
1013 """Properly register MODULE, NAME, and optional STUB qualification."""
1016 sys
.stub_modules
[name
] = theMod
1018 sys
.modules
[name
] = theMod
1019 if sys
.stub_modules
.has_key(name
):
1020 del sys
.stub_modules
[name
]
1022 def find_mod_registration(name
):
1023 """Find module named NAME sys.modules, .stub_modules, or on the stack."""
1024 if sys
.stub_modules
.has_key(name
):
1025 return sys
.stub_modules
[name
] # ==>
1026 elif sys
.modules
.has_key(name
):
1027 return sys
.modules
[name
] # ==>
1029 if stack
.in_process(name
):
1030 it
= stack
.mod(name
)
1034 raise ValueError, '%s %s in %s or %s' % (name
, # ==X
1039 def get_mod_attrs(theMod
, which
= None):
1040 """Get MODULE object's path, containing-package, and designated path.
1042 Virtual attribute USE_PATH is derived from PKG_PATH, MOD_PATHNAME,
1043 and/or sys.path, depending on the module type and settings."""
1044 it
= theMod
.__dict
__[IMP_ADMIN
]
1046 # Load path is either the explicitly designated load path for the
1047 # package, or else the directory in which it resides:
1048 if which
== USE_PATH
:
1050 # Return explicitly designated path:
1051 return it
[PKG_PATH
] # ==>
1052 if it
[MOD_PATHNAME
]:
1053 if it
[MOD_TYPE
] == PY_PACKAGE
:
1054 # Return the package's directory path:
1055 return [it
[MOD_PATHNAME
]] # ==>
1057 # Return the directory where the module resides:
1058 return [os
.path
.split(it
[MOD_PATHNAME
])[0]] # ==>
1059 # No explicitly designated path - use sys.path, eg for system
1062 return it
[which
] # ==>
1066 def set_mod_attrs(theMod
, path
, pkg
, pkgPath
, ty
):
1067 """Register MOD import attrs PATH, PKG container, and PKGPATH, linking
1068 the package container into the module along the way."""
1069 theDict
= theMod
.__dict
__
1071 # Get existing one, if any:
1072 it
= theDict
[IMP_ADMIN
]
1074 # None existing, gen a new one:
1076 for fld
, val
in ((MOD_PATHNAME
, path
), (MOD_PACKAGE
, pkg
),
1077 (PKG_PATH
, pkgPath
), (MOD_TYPE
, ty
)):
1081 theDict
[IMP_ADMIN
] = it
1083 theDict
[PKG_NM
] = theDict
[PKG_SHORT_NM
] = pkg
1086 def format_tb_msg(tb
, recursive
):
1087 """This should be in traceback.py, and traceback.print_tb() should use it
1088 and traceback.extract_tb(), instead of print_tb() and extract_tb() having
1089 so much redundant code!"""
1090 tb_lines
, formed
= traceback
.extract_tb(tb
), ''
1091 for line
in tb_lines
:
1092 f
, lno
, nm
, ln
= line
1093 if f
[-1 * (len(__name__
) + 3):] == __name__
+ '.py':
1094 # Skip newimp notices - agregious hack, justified only by the fact
1095 # that this functionality will be properly doable in new impending
1096 # exception mechanism:
1098 formed
= formed
+ ('\n%s File "%s", line %d, in %s%s' %
1099 (((recursive
and '*') or ' '),
1101 ((ln
and '\n ' + string
.strip(ln
)) or '')))
1104 def import_trail_msg(msg
, tb
, modNm
):
1105 """Doctor an error message to include the path of the current import, and
1106 a sign that it is a circular import, if so."""
1109 (stack
.looped(modNm
) and stack
.in_process(modNm
))))
1111 def compile_source(sourcePath
, sourceFile
):
1112 """Given python code source path and file obj, Create a compiled version.
1114 Return path of compiled version, or None if file creation is not
1115 successful. (Compilation errors themselves are passed without restraint.)
1117 This is an import-private interface, and not well-behaved for general use.
1119 In particular, we presume the validity of the sourcePath, and that it
1120 includes a '.py' extension."""
1122 compiledPath
= sourcePath
[:-3] + '.pyc'
1124 compiledFile
= open(compiledPath
, 'wb')
1126 note("write permission denied to " + compiledPath
, 3)
1128 mtime
= os
.stat(sourcePath
)[8]
1131 compiled
= compile(sourceFile
.read(), sourcePath
, 'exec')
1133 # Doctor the exception a bit, to include the source file name in
1134 # the report, and then reraise the doctored version.
1135 os
.unlink(compiledFile
.name
)
1136 sys
.exc_value
= ((sys
.exc_value
[0] + ' in ' + sourceFile
.name
,)
1137 + sys
.exc_value
[1:])
1138 raise sys
.exc_type
, sys
.exc_value
# ==X
1140 # Ok, we have a valid compilation.
1142 compiledFile
.write(imp
.get_magic()) # compiled magic number
1143 compiledFile
.seek(8, 0) # mtime space holder
1144 marshal
.dump(compiled
, compiledFile
) # write the code obj
1145 compiledFile
.seek(4, 0) # position for mtime
1146 compiledFile
.write(marshal
.dumps(mtime
)[1:]) # register mtime
1147 compiledFile
.flush()
1148 compiledFile
.close()
1155 got_suffixes_dict
= {}
1156 def get_suffixes(ty
=None):
1157 """Produce a list of triples, each describing a type of import file.
1159 Triples have the form '(SUFFIX, MODE, TYPE)', where:
1161 SUFFIX is a string found appended to a module name to make a filename for
1162 that type of import file.
1164 MODE is the mode string to be passed to the built-in 'open' function - "r"
1165 for text files, "rb" for binary.
1167 TYPE is the file type:
1169 PY_SOURCE: python source code,
1170 PY_COMPILED: byte-compiled python source,
1171 C_EXTENSION: compiled-code object file,
1172 PY_PACKAGE: python library directory, or
1173 SEARCH_ERROR: no module found. """
1175 # Note: sorted_suffixes() depends on this function's value being invariant.
1176 # sorted_suffixes() must be revised if this becomes untrue.
1178 global got_suffixes
, got_suffixes_dict
1180 if not got_suffixes
:
1181 # Ensure that the .pyc suffix precedes the .py:
1182 got_suffixes
= [('', 'r', PY_PACKAGE
)]
1183 got_suffixes_dict
[PY_PACKAGE
] = ('', 'r', PY_PACKAGE
)
1185 for suff
in imp
.get_suffixes():
1186 got_suffixes_dict
[suff
[2]] = suff
1187 if suff
[0] == '.py':
1189 elif suff
[0] == '.pyc':
1192 got_suffixes
.append(suff
)
1193 got_suffixes
.append(pyc
)
1194 got_suffixes
.append(py
)
1196 return got_suffixes_dict
[ty
] # ==>
1198 return got_suffixes
# ==>
1201 sortedSuffs
= [] # State vars for sorted_suffixes(). Go
1202 def sorted_suffixes():
1203 """Helper function ~efficiently~ tracks sorted list of module suffixes."""
1205 # Produce sortedSuffs once - this presumes that get_suffixes does not
1206 # change from call to call during a python session. Needs to be
1207 # corrected if that becomes no longer true.
1210 if not sortedSuffs
: # do compute only the "first" time
1211 for item
in get_suffixes():
1212 sortedSuffs
.append(item
[0])
1213 # Sort them in descending order:
1214 sortedSuffs
.sort(lambda x
, y
: (((len(x
) > len(y
)) and 1) or
1215 ((len(x
) < len(y
)) and -1)))
1216 sortedSuffs
.reverse()
1220 def normalize_pathname(path
):
1221 """Given PATHNAME, return an absolute pathname relative to cwd, reducing
1222 unnecessary components where convenient (eg, on Unix)."""
1224 # We do a lot more when we have posix-style paths, eg os.sep == '/'.
1227 return os
.path
.join(os
.getcwd
, path
) # ==>
1229 outwards
, inwards
= 0, []
1230 for nm
in string
.splitfields(path
, os
.sep
):
1233 # Translate parent-dir entries to outward notches:
1235 # Pop a containing inwards:
1238 # Register leading outward notches:
1239 outwards
= outwards
+ 1
1242 inwards
= string
.joinfields(inwards
, os
.sep
)
1244 if (not inwards
) or (inwards
[0] != os
.sep
):
1245 # Relative path - join with current working directory, (ascending
1246 # outwards to account for leading parent-dir components):
1249 cwd
= string
.splitfields(cwd
, os
.sep
)
1250 cwd
= string
.joinfields(cwd
[:len(cwd
) - outwards
], os
.sep
)
1252 return os
.path
.join(cwd
, inwards
) # ==>
1256 return inwards
# ==>
1259 # exterior(): Utility routine, obtain local and global dicts of environment
1260 # containing/outside the callers environment, ie that of the
1261 # caller's caller. Routines can use exterior() to determine the
1262 # environment from which they were called.
1265 """Return dyad containing locals and globals of caller's caller.
1267 Locals will be None if same as globals, ie env is global env."""
1269 bogus
= 'bogus' # A locally usable exception
1270 try: raise bogus
# Force an exception object
1272 at
= sys
.exc_traceback
.tb_frame
.f_back
# The external frame.
1273 if at
.f_back
: at
= at
.f_back
# And further, if any.
1274 globals, locals = at
.f_globals
, at
.f_locals
1275 if locals == globals: # Exterior is global?
1277 return (locals, globals)
1279 #########################################################################
1280 # TESTING FACILITIES #
1282 def note(msg
, threshold
=2):
1283 if VERBOSE
>= threshold
: sys
.stderr
.write('(import: ' + msg
+ ')\n')
1286 """Populate a transient directory hierarchy according to a definition
1287 template - so we can create package/module hierarchies with which to
1288 exercise the new import facilities..."""
1290 def __init__(self
, template
, where
='/var/tmp'):
1291 """Establish a dir hierarchy, according to TEMPLATE, that will be
1292 deleted upon deletion of this object (or deliberate invocation of the
1294 self
.PKG_NM
= 'tdh_'
1296 while os
.path
.exists(os
.path
.join(where
, self
.PKG_NM
+str(rev
))):
1298 sys
.exc_traceback
= None # Ensure Discard of try/except obj ref
1299 self
.PKG_NM
= self
.PKG_NM
+ str(rev
)
1300 self
.root
= os
.path
.join(where
, self
.PKG_NM
)
1301 self
.createDir(self
.root
)
1305 """Cleanup the test hierarchy."""
1307 def add(self
, template
, root
=None):
1308 """Populate directory according to template dictionary.
1310 Keys indicate file names, possibly directories themselves.
1312 String values dictate contents of flat files.
1314 Dictionary values dictate recursively embedded dictionary templates."""
1315 if root
== None: root
= self
.root
1316 for key
, val
in template
.items():
1317 name
= os
.path
.join(root
, key
)
1318 if type(val
) == types
.StringType
: # flat file
1319 self
.createFile(name
, val
)
1320 elif type(val
) == types
.DictionaryType
: # embedded dir
1321 self
.createDir(name
)
1324 raise ValueError, ('invalid file-value type, %s' % # ==X
1326 def remove(self
, name
=''):
1327 """Dispose of the NAME (or keys in dictionary), using 'rm -r'."""
1328 name
= os
.path
.join(self
.root
, name
)
1329 sys
.exc_traceback
= None # Ensure Discard of try/except obj ref
1330 if os
.path
.exists(name
):
1331 print '(TestDirHier: eradicating %s)' % name
1332 os
.system('rm -r ' + name
)
1334 raise IOError, "can't remove non-existent " + name
# ==X
1335 def createFile(self
, name
, contents
=None):
1336 """Establish file NAME with CONTENTS.
1338 If no contents specfied, contents will be 'print NAME'."""
1341 f
.write("print '" + name
+ "'\n")
1345 def createDir(self
, name
):
1346 """Create dir with NAME."""
1347 return os
.mkdir(name
, 0755)
1351 def testExec(msg
, execList
, locals, globals):
1352 global skipToTest
, atTest
1353 print 'Import Test:', '(' + str(atTest
) + ')', msg
, '...'
1355 if skipToTest
> (atTest
- 1):
1356 print ' ... skipping til test', skipToTest
1360 for stmt
in execList
:
1361 exec stmt
in locals, globals
1363 def test(number
=0, leaveHiers
=0):
1364 """Exercise import functionality, creating a transient dir hierarchy for
1367 We actually install the new import functionality, temporarily, resuming the
1368 existing function on cleanup."""
1372 global skipToTest
, atTest
1376 def unloadFull(mod
):
1377 """Unload module and offspring submodules, if any."""
1379 if type(mod
) == types
.StringType
:
1381 elif type(mod
) == types
.ModuleType
:
1382 modNm
= modMod
.__name
__
1383 for subj
in sys
.modules
.keys() + sys
.stub_modules
.keys():
1384 if subj
[0:len(modNm
)] == modNm
:
1389 except AttributeError:
1390 __main__
.testMods
= []
1391 testMods
= __main__
.testMods
1394 # Install the newimp routines, within a try/finally:
1396 sys
.exc_traceback
= None
1397 wasImport
= __builtin__
.__import
__ # Stash default
1399 except AttributeError:
1402 hiers
= []; modules
= []
1404 wasVerbose
, VERBOSE
= VERBOSE
, 1
1405 __builtin__
.__import
__ = import_module
# Install new version
1407 if testMods
: # Clear out imports from previous tests
1408 for m
in testMods
[:]:
1414 testExec("already imported module: %s" % sys
.modules
.keys()[0],
1415 ['import ' + sys
.modules
.keys()[0]],
1416 vars(), newimp_globals
)
1417 no_sirree
= 'no_sirree_does_not_exist'
1420 testExec("non-existent module: %s" % no_sirree
,
1421 ['try: import ' + no_sirree
+
1422 '\nexcept ImportError: pass'],
1423 vars(), newimp_globals
)
1428 # Find a module that's not yet loaded, from a list of prospects:
1429 for mod
in ['Complex', 'UserDict', 'UserList', 'calendar',
1430 'cmd', 'dis', 'mailbox', 'profile', 'random', 'rfc822']:
1431 if not (mod
in sys
.modules
.keys()):
1435 testExec("not-yet loaded module: %s" % mod
,
1436 ['import ' + mod
, 'modules.append(got)'],
1437 vars(), newimp_globals
)
1439 testExec("not-yet loaded module: list exhausted, never mind",
1440 [], vars(), newimp_globals
)
1442 # Now some package stuff.
1446 # First change the path to include our temp dir, copying so the
1447 # addition can be revoked on cleanup in the finally, below:
1448 sys
.path
= ['/var/tmp'] + sys
.path
[:]
1449 # Now create a trivial package:
1450 stmts
= ["hier1 = TestDirHier({'a.py': 'print \"a.py executing\"'})",
1451 "hiers.append(hier1)",
1452 "base = hier1.PKG_NM",
1453 "exec 'import ' + base",
1454 "testMods.append(base)"]
1455 testExec("trivial package, with one module, a.py",
1456 stmts
, vars(), newimp_globals
)
1460 # Slightly less trivial package - reference to '__':
1461 stmts
= [("hier2 = TestDirHier({'ref.py': 'print \"Pkg __:\", __'})"),
1462 "base = hier2.PKG_NM",
1463 "hiers.append(hier2)",
1464 "exec 'import ' + base",
1465 "testMods.append(base)"]
1466 testExec("trivial package, with module that has pkg shorthand ref",
1467 stmts
, vars(), newimp_globals
)
1471 # Nested package, plus '__' references:
1473 complexTemplate
= {'ref.py': 'print "ref.py loading..."',
1474 'suite': {'s1.py': 'print "s1.py, in pkg:", __',
1475 'subsuite': {'sub1.py':
1476 'print "sub1.py"'}}}
1477 stmts
= [('print """%s\n%s\n%s\n%s\n%s\n%s"""' %
1479 ' ref.py\t\t\t"ref.py loading..."',
1481 ' s1.py \t\t"s1.py, in pkg: xxxx.suite"',
1483 ' sub1.py "sub1.py" ')),
1484 "hier3 = TestDirHier(complexTemplate)",
1485 "base = hier3.PKG_NM",
1486 "hiers.append(hier3)",
1487 "exec 'import ' + base",
1488 "testMods.append(base)"]
1489 testExec("Significantly nestled package:",
1490 stmts
, vars(), newimp_globals
)
1494 # Try an elaborate hierarchy which includes an __init__ master in one
1495 # one portion, a ref across packages within the hierarchies, and an
1496 # indirect recursive import which cannot be satisfied (and hence,
1497 # prevents load of part of the hierarchy).
1498 complexTemplate
= {'mid':
1500 {'__init__.py': 'import __.easy, __.nother',
1501 'easy.py': 'print "easy.py:", __name__',
1502 'nother.py': ('%s\n%s\n%s\n' %
1504 'print "nother got __.easy"',
1505 # __.__.awry should be found but
1506 # should not load successfully,
1507 # disrupting nother, but not easy
1508 'import __.__.awry'))},
1509 # continuing dict 'mid':
1513 ('print "got " + __name__',
1514 'from __ import *')),
1515 # This mutual recursion (b->a, a->d->b) should be
1516 # ok, since a.py sets ax before recursing.
1517 'a.py': 'ax = 1; from __.b import bx',
1518 'b.py': 'bx = 1; from __.a import ax'}}}
1519 stmts
= ["hier5 = TestDirHier(complexTemplate)",
1520 "base = hier5.PKG_NM",
1521 "testMods.append(base)",
1522 "hiers.append(hier5)",
1523 "exec 'import %s.mid.prime' % base",
1524 "print eval(base)", # Verify the base was bound
1525 "testMods.append(base)"]
1526 testExec("Elaborate, clean hierarchy",
1527 stmts
, vars(), newimp_globals
)
1531 # Here we disrupt the mutual recursion in the mid.awry package, so the
1532 # import should now fail.
1533 complexTemplate
['mid']['awry']['a.py'] = 'from __.b import bx; ax = 1'
1534 complexTemplate
['mid']['awry']['b.py'] = 'from __.a import ax; bx = 1'
1535 stmts
= ["hier6 = TestDirHier(complexTemplate)",
1536 "base = hier6.PKG_NM",
1537 "testMods.append(base)",
1538 "hiers.append(hier6)",
1539 "work = ('import %s.mid.prime' % base)",
1541 "\nexcept ImportError: print ' -- import failed, as ought'" +
1542 "\nelse: raise SystemError, sys.exc_value"),
1543 "testMods.append(base)"]
1544 testExec("Elaborate hier w/ deliberately flawed import recursion",
1545 stmts
, vars(), newimp_globals
)
1547 sys
.exc_traceback
= None # Signify clean conclusion.
1553 VERBOSE
= wasVerbose
1554 if wasImport
: # Resurrect prior routine
1555 __builtin__
.__import
__ = wasImport
1557 del __builtin__
.__import
__
1559 print 'Cleanup inhibited'
1561 if sys
.exc_traceback
:
1562 print ' ** Import test FAILURE... cleanup.'
1564 print ' Import test SUCCESS... cleanup'
1565 for h
in hiers
: h
.remove(); del h
# Dispose of test directories
1569 if __name__
== '__main__':