Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1 | """Prototype of 'import' functionality enhanced to implement packages. |
| 2 | |
| 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 |
| 8 | another. |
| 9 | |
| 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. |
| 17 | |
| 18 | Usage: once installed (newimp.install(); newimp.revert() to revert to |
| 19 | the prior __import__ routine), 'import ...' and 'from ... import ...' |
| 20 | can be used to: |
| 21 | |
| 22 | - import modules from the search path, as before. |
| 23 | |
| 24 | - import modules from within other directory "packages" on the search |
| 25 | path using a '.' dot-delimited nesting syntax. The nesting is fully |
| 26 | recursive. |
| 27 | |
Guido van Rossum | 96044da | 1995-04-07 09:06:50 +0000 | [diff] [blame] | 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 |
| 33 | 'test.test_types'. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 34 | |
| 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. |
| 38 | |
Guido van Rossum | 96044da | 1995-04-07 09:06:50 +0000 | [diff] [blame] | 39 | The '__' package references are actually names assigned within |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 40 | modules, to refer to their containing package. This means that |
Guido van Rossum | 96044da | 1995-04-07 09:06:50 +0000 | [diff] [blame] | 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'. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 45 | |
Guido van Rossum | 96044da | 1995-04-07 09:06:50 +0000 | [diff] [blame] | 46 | - import an entire package as a unit, by importing the package directory. |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 47 | If there is a module named '__init__.py' in the package, it controls the |
Guido van Rossum | 96044da | 1995-04-07 09:06:50 +0000 | [diff] [blame] | 48 | load. Otherwise, all the modules in the dir, including packages, are |
| 49 | inherently loaded into the package module's namespace. |
| 50 | |
| 51 | For example, 'import test' will load the modules of the entire 'test' |
| 52 | package, at least until a test failure is encountered. |
| 53 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 54 | In a package, a module with the name '__init__' has a special role. |
Guido van Rossum | 96044da | 1995-04-07 09:06:50 +0000 | [diff] [blame] | 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 |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 57 | enables the __init__ module to control the load, possibly loading |
Guido van Rossum | 96044da | 1995-04-07 09:06:50 +0000 | [diff] [blame] | 58 | the entire directory deliberately (using 'import __', or even |
| 59 | 'from __ import *', to load all the module contents directly into the |
| 60 | package module). |
| 61 | |
| 62 | - perform any combination of the above - have a package that contains |
| 63 | packages, etc. |
| 64 | |
| 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 |
| 69 | found.""" |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 70 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 71 | __version__ = "$Revision$" |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 72 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 73 | # $Id$ First release: |
| 74 | # Ken.Manheimer@nist.gov, 5-Apr-1995, for python 1.2 |
| 75 | |
| 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 |
| 81 | # platform dir. |
| 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. ??? |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 90 | |
| 91 | # Developers Notes: |
| 92 | # |
| 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. |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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 |
| 101 | # the phases. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 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. |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 115 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 116 | try: |
| 117 | VERBOSE |
| 118 | except NameError: |
| 119 | VERBOSE = 0 # Will be reset by init(1), also. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 120 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 121 | import sys, string, regex, types, os, marshal, traceback |
| 122 | import __main__, __builtin__ |
| 123 | |
| 124 | newimp_globals = vars() |
| 125 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 126 | try: |
| 127 | import imp # Build on this recent addition |
| 128 | except ImportError: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 129 | raise ImportError, 'Pkg import module depends on optional "imp" module'#==X |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 130 | |
| 131 | from imp import SEARCH_ERROR, PY_SOURCE, PY_COMPILED, C_EXTENSION |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 132 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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: |
| 137 | envDict[varNm] = val |
| 138 | |
| 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 |
| 143 | # __root__: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 144 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 145 | locals, globals = vars(), newimp_globals |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 146 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 147 | if full_reset: |
| 148 | global VERBOSE |
| 149 | VERBOSE = 0 |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 150 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 155 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 156 | # Environment setup - "root" module, '__root__' |
| 157 | # Establish root package '__root__' in __main__ and newimp envs. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 158 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 164 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 165 | # Name of controlling module for a package, if any: |
| 166 | defvar('INIT_MOD_NM', globals, "__init__", full_reset) |
| 167 | |
| 168 | # Paths eventually will be extended to accomodate non-filesystem media - |
| 169 | # eg, URLs, composite objects, who knows. |
| 170 | |
| 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) |
| 174 | if full_reset: |
| 175 | defvar(IMP_SYS_NM, sys.__dict__, {MOD_LOAD_HOOKS: {}}, full_reset) |
| 176 | |
| 177 | |
| 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) |
| 191 | |
| 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__ |
| 198 | |
| 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 |
| 201 | # sys.path. |
| 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) |
| 205 | |
| 206 | try: |
| 207 | __builtin__.__import__ |
| 208 | defvar('origImportFunc', globals, __builtin__.__import__) |
| 209 | defvar('origReloadFunc', globals, __builtin__.reload) |
| 210 | except AttributeError: |
| 211 | pass |
| 212 | |
| 213 | defvar('PY_PACKAGE', globals, 4, full_reset) |
| 214 | defvar('PY_FROZEN', globals, 5, full_reset) |
| 215 | defvar('PY_BUILTIN', globals, 6, full_reset) |
| 216 | |
| 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'}, |
| 226 | full_reset) |
| 227 | |
| 228 | defvar('stack', globals, ImportStack(), full_reset) |
| 229 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 230 | def install(): |
| 231 | """Install newimp import_module() routine, for package support. |
| 232 | |
| 233 | newimp.revert() reverts to __import__ routine that was superceded.""" |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 234 | __builtin__.__import__ = import_module |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 235 | __builtin__.reload = reload |
| 236 | __builtin__.unload = unload |
| 237 | __builtin__.bypass = bypass |
| 238 | return 'Enhanced import functionality in place.' |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 239 | def revert(): |
| 240 | """Revert to original __builtin__.__import__ func, if newimp.install() has |
| 241 | been executed.""" |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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.' |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 248 | |
| 249 | def import_module(name, |
| 250 | envLocals=None, envGlobals=None, |
| 251 | froms=None, |
| 252 | inPkg=None): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 253 | """Primary service routine implementing 'import' with package nesting. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 254 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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()). |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 260 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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. |
| 266 | |
| 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.""" |
| 270 | |
| 271 | rootMod = sys.modules[ROOT_MOD_NM] |
| 272 | |
| 273 | note("import_module: seeking '%s'" % name, 1) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 274 | |
| 275 | # We need callers environment dict for local path and resulting module |
| 276 | # binding. |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 277 | if not envGlobals: |
| 278 | # This should not happen, but does for imports called from within |
| 279 | # functions. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 280 | envLocals, envGlobals = exterior() |
| 281 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 282 | if inPkg: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 283 | pkg = inPkg |
| 284 | elif envGlobals.has_key(PKG_NM): |
| 285 | pkg = envGlobals[PKG_NM] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 286 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 287 | # ** KLUDGE - cover for modules that lack package attributes: |
| 288 | pkg = rootMod |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 289 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 290 | if pkg != rootMod: |
| 291 | note(' - relative to package %s' % pkg) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 292 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 293 | modList = theMod = absNm = nesting = None |
| 294 | |
| 295 | # Normalize |
| 296 | # - absNm is absolute w.r.t. __root__ |
| 297 | # - relNm is relative w.r.t. pkg. |
| 298 | if inPkg: |
| 299 | absNm, relNm = pkg.__name__ + '.' + name, name |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 300 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 301 | absNm, relNm, pkg = normalize_import_ref(name, pkg) |
| 302 | note("Normalized: %s%s" % (absNm, (((relNm != absNm) |
| 303 | and (" ('%s' in %s)" % (relNm, pkg))) |
| 304 | or '')), 3) |
| 305 | |
| 306 | pkgPath = get_mod_attrs(pkg, USE_PATH) |
| 307 | |
| 308 | try: # try...finally guards import stack integrity. |
| 309 | |
| 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' % |
| 316 | absNm) |
| 317 | theMod = stack.mod(absNm) |
| 318 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 319 | else: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 320 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 326 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 327 | else: # Actually do load, of one sort or another: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 328 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 329 | # Seek builtin or frozen first: |
| 330 | theMod = imp.init_builtin(absNm) |
| 331 | if theMod: |
| 332 | set_mod_attrs(theMod, None, pkg, None, PY_BUILTIN) |
| 333 | stack.mod(absNm, theMod) |
| 334 | note('found builtin ' + absNm) |
| 335 | else: |
| 336 | theMod = imp.init_frozen(absNm) |
| 337 | if theMod: |
| 338 | set_mod_attrs(theMod, None, pkg, None, PY_FROZEN) |
| 339 | stack.mod(absNm, theMod) |
| 340 | note('found frozen ' + absNm) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 341 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 342 | if not theMod: |
| 343 | # Not already-loaded, in-process, builtin, or frozen - |
| 344 | # we're seeking in the outside world (filesystem): |
| 345 | |
| 346 | if sys.stub_modules.has_key(absNm): |
| 347 | |
| 348 | # A package for which we have a stub: |
| 349 | theMod = reload(sys.stub_modules[absNm], inPkg) |
| 350 | |
| 351 | else: |
| 352 | |
| 353 | # Now we actually search the fs. |
| 354 | |
| 355 | if type(pkgPath) == types.StringType: |
| 356 | pkgPath = [pkgPath] |
| 357 | |
| 358 | # Find a path leading to the module: |
| 359 | modList = find_module(relNm, pkgPath, absNm) |
| 360 | if not modList: |
| 361 | raise ImportError, ("module '%s' not found" % #==X |
| 362 | absNm) |
| 363 | |
| 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) |
| 367 | |
| 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)) |
| 371 | |
| 372 | # Establish the module object in question: |
| 373 | theMod = procure_module(absNm) |
| 374 | stack.mod(absNm, theMod) |
| 375 | |
| 376 | # Do the load: |
| 377 | theMod = load_module(theMod, ty[2], modf, inPkg) |
| 378 | |
| 379 | commit_mod_containment(absNm) |
| 380 | |
| 381 | # Successful load - promote to fully-imported status: |
| 382 | register_module(theMod, theMod.__name__) |
| 383 | |
| 384 | |
| 385 | # We have a loaded module (perhaps stub): situate specified components, |
| 386 | # and return appropriate thing. According to guido: |
| 387 | # |
| 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 |
| 392 | # way." |
| 393 | # *** The above rationale should probably be reexamined, since newimp |
| 394 | # actually takes care of populating the caller's namespace. |
| 395 | |
| 396 | if not froms: |
| 397 | |
| 398 | # Return the outermost container, possibly stub: |
| 399 | if nesting: |
| 400 | return find_mod_registration(nesting[0][0]) |
Guido van Rossum | b1c1315 | 1995-05-05 15:50:56 +0000 | [diff] [blame] | 401 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 402 | return find_mod_registration(string.splitfields(absNm,'.')[0]) |
| 403 | else: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 404 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 405 | return theMod |
| 406 | |
| 407 | finally: # Decrement stack registration: |
| 408 | stack.pop(absNm) |
| 409 | |
| 410 | |
| 411 | def reload(module, inPkg = None): |
| 412 | """Re-parse and re-initialize an already (or partially) imported MODULE. |
| 413 | |
| 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. |
| 417 | |
| 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. |
| 421 | |
| 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. |
| 425 | |
| 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 |
| 434 | desired. |
| 435 | |
| 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. |
| 441 | |
| 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. |
| 447 | |
| 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.""" |
| 452 | |
| 453 | if type(module) == types.StringType: |
| 454 | theMod = find_mod_registration(module) |
| 455 | elif type(module) == types.ModuleType: |
| 456 | theMod = module |
| 457 | else: |
| 458 | raise ImportError, '%s not already imported' # ==X |
| 459 | |
| 460 | if theMod in [sys.modules[ROOT_MOD_NM], sys.modules['__builtin__']]: |
| 461 | raise ImportError, 'cannot re-init internal module' # ==X |
| 462 | |
| 463 | try: |
| 464 | thePath = get_mod_attrs(theMod, MOD_PATHNAME) |
| 465 | except KeyError: |
| 466 | thePath = None |
| 467 | |
| 468 | if not thePath: |
| 469 | # If we have no path for the module, we can only reload it from |
| 470 | # scratch: |
| 471 | note('no pathname registered for %s, doing full reload' % theMod) |
| 472 | unload(theMod) |
| 473 | envGlobals, envLocals = exterior() |
| 474 | return import_module(theMod.__name__, |
| 475 | envGlobals, envLocals, None, inPkg) |
| 476 | else: |
| 477 | |
| 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) |
| 483 | else: |
| 484 | openFile = open(thePath, get_suffixes(ty)[1]) |
| 485 | return load_module(theMod, # ==> |
| 486 | ty, |
| 487 | openFile, |
| 488 | inPkg) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 489 | def unload(module): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 490 | """Remove registration for a module, so import will do a fresh load. |
| 491 | |
| 492 | Returns the module registries (sys.modules and/or sys.stub_modules) where |
| 493 | it was found.""" |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 494 | if type(module) == types.ModuleType: |
| 495 | module = module.__name__ |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 496 | gotit = [] |
| 497 | for which in ['sys.modules', 'sys.stub_modules']: |
| 498 | m = eval(which) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 499 | try: |
| 500 | del m[module] |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 501 | gotit.append(which) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 502 | except KeyError: |
| 503 | pass |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 504 | if not gotit: |
| 505 | raise ValueError, '%s not a module or a stub' % module # ==X |
| 506 | else: return gotit |
| 507 | def bypass(modNm): |
| 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) |
| 511 | else: |
| 512 | sys.modules[modNm] = imp.new_module('bypass()ed module %s' % modNm) |
| 513 | commit_mod_containment(modNm) |
| 514 | |
| 515 | |
| 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.""" |
| 519 | |
| 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: |
| 524 | if inwards: |
| 525 | # Pop a containing inwards: |
| 526 | del inwards[-1] |
| 527 | else: |
| 528 | # (Effectively) leading '__' - notch outwards: |
| 529 | outwards = outwards + 1 |
| 530 | else: |
| 531 | inwards.append(nm) |
| 532 | inwards = string.joinfields(inwards, '.') |
| 533 | |
| 534 | # Now identify the components: |
| 535 | |
| 536 | if not outwards: |
| 537 | pkg = sys.modules[ROOT_MOD_NM] |
| 538 | else: |
| 539 | while outwards > 1: |
| 540 | pkg = pkg.__dict__[PKG_NM] # We'll just loop at top |
| 541 | if pkg == __root__: |
| 542 | break # ==v |
| 543 | outwards = outwards - 1 |
| 544 | |
| 545 | if not inwards: # Entire package: |
| 546 | return pkg.__name__, pkg.__name__, pkg # ==> |
| 547 | else: # Name relative to package: |
| 548 | if pkg == __root__: |
| 549 | return inwards, inwards, pkg # ==> |
| 550 | else: |
| 551 | return pkg.__name__ + '.' + inwards, inwards, pkg # ==> |
| 552 | |
| 553 | class ImportStack: |
| 554 | """Provide judicious support for mutually recursive import loops. |
| 555 | |
| 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.""" |
| 563 | |
| 564 | def __init__(self): |
| 565 | self._cycles = {} |
| 566 | self._mods = {} |
| 567 | self._looped = [] |
| 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 |
| 582 | return 1 # ==> |
| 583 | else: |
| 584 | self._cycles[modNm] = 1 |
| 585 | return 0 # ==> |
| 586 | def mod(self, modNm, mod=None): |
| 587 | """Associate MOD-NAME with MODULE, for easy reference.""" |
| 588 | if mod: |
| 589 | self._mods[modNm] = mod |
| 590 | else: |
| 591 | try: |
| 592 | return self._mods[modNm] # ==> |
| 593 | except KeyError: |
| 594 | return None |
| 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 |
| 599 | if amt < 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] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 609 | |
| 610 | def find_module(name, path, absNm=''): |
| 611 | """Locate module NAME on PATH. PATH is pathname string or a list of them. |
| 612 | |
| 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 |
| 615 | possible. |
| 616 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 617 | Returns a list of the tuples returned by 'find_mod_file()', one for |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 618 | each nested level, deepest last.""" |
| 619 | |
| 620 | checked = [] # For avoiding redundant dir lists. |
| 621 | |
| 622 | if not absNm: absNm = name |
| 623 | |
| 624 | # Parse name into list of nested components, |
| 625 | expNm = string.splitfields(name, '.') |
| 626 | |
| 627 | for curPath in path: |
| 628 | |
| 629 | if (type(curPath) != types.StringType) or (curPath in checked): |
| 630 | # Disregard bogus or already investigated path elements: |
| 631 | continue # ==^ |
| 632 | else: |
| 633 | # Register it for subsequent disregard. |
| 634 | checked.append(curPath) |
| 635 | |
| 636 | if len(expNm) == 1: |
| 637 | |
| 638 | # Non-nested module name: |
| 639 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 640 | got = find_mod_file(curPath, absNm) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 641 | if got: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 642 | note('using %s' % got[2], 3) |
| 643 | return [got] # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 644 | |
| 645 | else: |
| 646 | |
| 647 | # Composite name specifying nested module: |
| 648 | |
| 649 | gotList = []; nameAccume = expNm[0] |
| 650 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 651 | got = find_mod_file(curPath, nameAccume) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 652 | if not got: # Continue to next prospective path. |
| 653 | continue # ==^ |
| 654 | else: |
| 655 | gotList.append(got) |
| 656 | nm, file, fullPath, ty = got |
| 657 | |
| 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 |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 663 | break # ==v |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 664 | if nameAccume: |
| 665 | nameAccume = nameAccume + '.' + component |
| 666 | else: |
| 667 | nameAccume = component |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 668 | got = find_mod_file(fullPath, nameAccume) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 669 | if got: |
| 670 | gotList.append(got) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 671 | nm, file, fullPath, ty = got |
| 672 | else: |
| 673 | # Clear state vars: |
| 674 | gotList, got, nameAccume = [], None, '' |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 675 | break # ==v |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 676 | # Found nesting all the way to the specified tip: |
| 677 | if got: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 678 | return gotList # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 679 | |
| 680 | # Failed. |
| 681 | return None |
| 682 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 683 | def find_mod_file(pathNm, modname): |
| 684 | """Find right module file given DIR and module NAME, compiling if needed. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 685 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 686 | If successful, returns quadruple consisting of: |
| 687 | - mod name, |
| 688 | - file object, |
| 689 | - full pathname for the found file, |
| 690 | - a description triple as contained in the list returned by get_suffixes. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 691 | |
| 692 | Otherwise, returns None. |
| 693 | |
| 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 |
| 696 | possible.""" |
| 697 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 698 | relNm = modname[1 + string.rfind(modname, '.'):] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 699 | |
| 700 | for suff, mode, ty in get_suffixes(): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 701 | fullPath = os.path.join(pathNm, relNm + suff) |
| 702 | note('trying ' + fullPath + '...', 4) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 703 | try: |
| 704 | modf = open(fullPath, mode) |
| 705 | except IOError: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 706 | # ** ?? Skip unreadable ones: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 707 | continue # ==^ |
| 708 | |
| 709 | if ty == PY_PACKAGE: |
| 710 | # Enforce directory characteristic: |
| 711 | if not os.path.isdir(fullPath): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 712 | note('Skipping non-dir match ' + fullPath, 3) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 713 | continue # ==^ |
| 714 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 715 | return (modname, modf, fullPath, (suff, mode, ty)) # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 716 | |
| 717 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 718 | elif ty in [PY_SOURCE, PY_COMPILED]: |
| 719 | usePath, useTy, openFile = prefer_compiled(fullPath, ty) |
| 720 | return (modname, # ==> |
| 721 | openFile, |
| 722 | usePath, |
| 723 | get_suffixes(useTy)) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 724 | |
| 725 | elif ty == C_EXTENSION: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 726 | note('found C_EXTENSION ' + fullPath, 3) |
| 727 | return (modname, modf, fullPath, (suff, mode, ty)) # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 728 | |
| 729 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 730 | raise SystemError, 'Unanticipated module type encountered' # ==X |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 731 | |
| 732 | return None |
| 733 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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.""" |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 738 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 739 | if ty == PY_SOURCE: |
| 740 | if not modf: |
| 741 | try: |
| 742 | modf = open(path, 'r') |
| 743 | except IOError: |
| 744 | pass |
| 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])): |
| 750 | # Try to compile: |
| 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) |
| 756 | try: |
| 757 | return (pyc, PY_COMPILED, open(pyc, 'rb')) # ==> |
| 758 | except IOError: |
| 759 | if modf: |
| 760 | return (path, PY_SOURCE, modf) # ==> |
| 761 | else: |
| 762 | raise ImportError, 'Failed acces to .py and .pyc' # ==X |
| 763 | else: |
| 764 | note("couldn't get newer compiled, using PY_SOURCE", 3) |
| 765 | if modf: |
| 766 | return (path, PY_SOURCE, modf) # ==> |
| 767 | else: |
| 768 | raise ImportError, 'Failed acces to .py and .pyc' # ==X |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 769 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 770 | elif ty == PY_COMPILED: |
| 771 | note('working from PY_COMPILED', 3) |
| 772 | if not modf: |
| 773 | try: |
| 774 | modf = open(path, 'rb') |
| 775 | except IOError: |
| 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')) |
| 787 | if pyc: |
| 788 | return (pyc, PY_COMPILED, modf) # ==> |
| 789 | else: |
| 790 | note('failed compile - must use more recent .py', 3) |
| 791 | return (py, PY_SOURCE, open(py, 'r')) # ==> |
| 792 | else: |
| 793 | return (path, PY_COMPILED, modf) # ==> |
| 794 | |
| 795 | def load_module(theMod, ty, theFile, fromMod): |
| 796 | """Load module NAME, of TYPE, from FILE, within MODULE. |
| 797 | |
| 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. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 800 | |
| 801 | Return the populated module object.""" |
| 802 | |
| 803 | # Note: we mint and register intermediate package directories, as necessary |
| 804 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 805 | name = theMod.__name__ |
| 806 | nameTail = name[1 + string.rfind(name, '.'):] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 807 | thePath = theFile.name |
| 808 | |
| 809 | if ty == PY_SOURCE: |
| 810 | exec_into(theFile, theMod, theFile.name) |
| 811 | |
| 812 | elif ty == PY_COMPILED: |
| 813 | pyc = open(theFile.name, 'rb').read() |
| 814 | if pyc[0:4] != imp.get_magic(): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 815 | raise ImportError, 'bad magic number: ' + theFile.name # ==X |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 816 | code = marshal.loads(pyc[8:]) |
| 817 | exec_into(code, theMod, theFile.name) |
| 818 | |
| 819 | elif ty == C_EXTENSION: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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. |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 828 | try: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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: |
| 832 | protMod = None |
| 833 | if nameTail != name: |
| 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 |
| 839 | # new one: |
| 840 | sys.modules[nameTail] = theMod |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 841 | theMod = imp.load_dynamic(nameTail, thePath, theFile) |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 842 | theMod.__name__ = name |
| 843 | # Cleanup dynamic mod's bogus self-registration, if necessary: |
| 844 | if nameTail != name: |
| 845 | if protMod: |
| 846 | # ... reinstating the one that was already there... |
| 847 | sys.modules[nameTail] = protMod |
| 848 | else: |
| 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 |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 857 | except: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 858 | # Provide import-nesting info, including signs of circularity: |
Guido van Rossum | 7f64e24 | 1995-07-12 15:34:34 +0000 | [diff] [blame^] | 859 | raise sys.exc_type, import_trail_msg(str(sys.exc_value),# ==X |
| 860 | sys.exc_traceback, |
| 861 | name) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 862 | elif ty == PY_PACKAGE: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 863 | # Load package constituents, doing the controlling module *if* it |
| 864 | # exists *and* it isn't already in process: |
| 865 | |
| 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) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 870 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 871 | note('skipping already-in-process %s.%s' % (theMod.__name__, |
| 872 | INIT_MOD_NM)) |
| 873 | got = {} |
| 874 | if init_mod_f: |
| 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__, |
| 881 | None, |
| 882 | theMod) |
| 883 | else: |
| 884 | # ... or else recursively load all constituent modules, except |
| 885 | # __init__: |
| 886 | for prospect in mod_prospects(thePath): |
| 887 | if prospect != INIT_MOD_NM: |
| 888 | import_module(prospect, |
| 889 | theMod.__dict__, theMod.__dict__, |
| 890 | None, |
| 891 | theMod) |
| 892 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 893 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 894 | raise ImportError, 'Unimplemented import type: %s' % ty # ==X |
| 895 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 896 | return theMod |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 897 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 898 | def exec_into(obj, module, path): |
| 899 | """Helper for load_module, execfile/exec path or code OBJ within MODULE.""" |
| 900 | |
| 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. |
| 904 | |
| 905 | try: |
| 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__ |
| 910 | except: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 911 | # Make the error message nicer? |
| 912 | raise sys.exc_type, import_trail_msg(str(sys.exc_value), # ==X |
| 913 | sys.exc_traceback, |
| 914 | module.__name__) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 915 | |
| 916 | |
| 917 | def mod_prospects(path): |
| 918 | """Return a list of prospective modules within directory PATH. |
| 919 | |
| 920 | We actually return the distinct names resulting from stripping the dir |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 921 | entries (excluding os.curdir and os.pardir) of their suffixes (as |
| 922 | represented by 'get_suffixes'). |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 923 | |
| 924 | (Note that matches for the PY_PACKAGE type with null suffix are |
| 925 | implicitly constrained to be directories.)""" |
| 926 | |
| 927 | # We actually strip the longest matching suffixes, so eg 'dbmmodule.so' |
| 928 | # mates with 'module.so' rather than '.so'. |
| 929 | |
| 930 | dirList = os.listdir(path) |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 931 | excludes = [os.curdir, os.pardir] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 932 | sortedSuffs = sorted_suffixes() |
| 933 | entries = [] |
| 934 | for item in dirList: |
| 935 | if item in excludes: continue # ==^ |
| 936 | for suff in sortedSuffs: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 937 | # *** ?? maybe platform-specific: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 938 | sub = -1 * len(suff) |
| 939 | if sub == 0: |
| 940 | if os.path.isdir(os.path.join(path, item)): |
| 941 | entries.append(item) |
| 942 | elif item[sub:] == suff: |
| 943 | it = item[:sub] |
| 944 | if not it in entries: |
| 945 | entries.append(it) |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 946 | break # ==v |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 947 | return entries |
| 948 | |
| 949 | |
| 950 | |
| 951 | def procure_module(name): |
| 952 | """Return an established or else new module object having NAME. |
| 953 | |
| 954 | First checks sys.modules, then sys.stub_modules.""" |
| 955 | |
| 956 | if sys.modules.has_key(name): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 957 | return sys.modules[name] # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 958 | elif sys.stub_modules.has_key(name): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 959 | return sys.stub_modules[name] # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 960 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 961 | return (stack.mod(name) or imp.new_module(name)) # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 962 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 963 | def commit_mod_containment(name): |
| 964 | """Bind a module object and its containers within their respective |
| 965 | containers.""" |
| 966 | cume, pkg = '', find_mod_registration(ROOT_MOD_NM) |
| 967 | for next in string.splitfields(name, '.'): |
| 968 | if cume: |
| 969 | cume = cume + '.' + next |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 970 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 971 | cume = next |
| 972 | cumeMod = find_mod_registration(cume) |
| 973 | pkg.__dict__[next] = cumeMod |
| 974 | pkg = cumeMod |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 975 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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. |
| 980 | |
| 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().""" |
| 984 | nesting = [] |
| 985 | |
| 986 | for modNm, modF, path, ty in modList: |
| 987 | |
| 988 | relNm = modNm[1 + string.rfind(modNm, '.'):] |
| 989 | |
| 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] |
| 996 | pkg = theMod |
| 997 | else: |
| 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), |
| 1003 | pkg, None, ty[2]) |
| 1004 | if ty[2] == PY_PACKAGE: |
| 1005 | # Register as a stub: |
| 1006 | register_module(theMod, modNm, 1) |
| 1007 | pkg = theMod |
| 1008 | nesting.append((theMod.__name__,relNm)) |
| 1009 | |
| 1010 | return nesting |
| 1011 | |
| 1012 | def register_module(theMod, name, stub=0): |
| 1013 | """Properly register MODULE, NAME, and optional STUB qualification.""" |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1014 | |
| 1015 | if stub: |
| 1016 | sys.stub_modules[name] = theMod |
| 1017 | else: |
| 1018 | sys.modules[name] = theMod |
| 1019 | if sys.stub_modules.has_key(name): |
| 1020 | del sys.stub_modules[name] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1021 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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] # ==> |
| 1028 | else: |
| 1029 | if stack.in_process(name): |
| 1030 | it = stack.mod(name) |
| 1031 | if it: |
| 1032 | return it # ==> |
| 1033 | else: |
| 1034 | raise ValueError, '%s %s in %s or %s' % (name, # ==X |
| 1035 | 'not registered', |
| 1036 | 'sys.modules', |
| 1037 | 'sys.stub_modules') |
| 1038 | |
| 1039 | def get_mod_attrs(theMod, which = None): |
| 1040 | """Get MODULE object's path, containing-package, and designated path. |
| 1041 | |
| 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] |
| 1045 | if which: |
| 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: |
| 1049 | if it[PKG_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]] # ==> |
| 1056 | else: |
| 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 |
| 1060 | # modules, etc: |
| 1061 | return sys.path |
| 1062 | return it[which] # ==> |
| 1063 | else: |
| 1064 | return it # ==> |
| 1065 | |
| 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__ |
| 1070 | try: |
| 1071 | # Get existing one, if any: |
| 1072 | it = theDict[IMP_ADMIN] |
| 1073 | except KeyError: |
| 1074 | # None existing, gen a new one: |
| 1075 | it = [None] * 4 |
| 1076 | for fld, val in ((MOD_PATHNAME, path), (MOD_PACKAGE, pkg), |
| 1077 | (PKG_PATH, pkgPath), (MOD_TYPE, ty)): |
| 1078 | if val: |
| 1079 | it[fld] = val |
| 1080 | |
| 1081 | theDict[IMP_ADMIN] = it |
| 1082 | if pkg: |
| 1083 | theDict[PKG_NM] = theDict[PKG_SHORT_NM] = pkg |
| 1084 | return it # ==> |
| 1085 | |
| 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: |
| 1097 | continue |
| 1098 | formed = formed + ('\n%s File "%s", line %d, in %s%s' % |
| 1099 | (((recursive and '*') or ' '), |
| 1100 | f, lno, nm, |
| 1101 | ((ln and '\n ' + string.strip(ln)) or ''))) |
| 1102 | return formed |
| 1103 | |
| 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.""" |
| 1107 | return (msg + |
| 1108 | format_tb_msg(tb, |
| 1109 | (stack.looped(modNm) and stack.in_process(modNm)))) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1110 | |
| 1111 | def compile_source(sourcePath, sourceFile): |
| 1112 | """Given python code source path and file obj, Create a compiled version. |
| 1113 | |
| 1114 | Return path of compiled version, or None if file creation is not |
| 1115 | successful. (Compilation errors themselves are passed without restraint.) |
| 1116 | |
| 1117 | This is an import-private interface, and not well-behaved for general use. |
| 1118 | |
| 1119 | In particular, we presume the validity of the sourcePath, and that it |
| 1120 | includes a '.py' extension.""" |
| 1121 | |
| 1122 | compiledPath = sourcePath[:-3] + '.pyc' |
| 1123 | try: |
| 1124 | compiledFile = open(compiledPath, 'wb') |
| 1125 | except IOError: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1126 | note("write permission denied to " + compiledPath, 3) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1127 | return None |
| 1128 | mtime = os.stat(sourcePath)[8] |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1129 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1130 | try: |
Guido van Rossum | f4ef7e6 | 1995-06-22 18:50:15 +0000 | [diff] [blame] | 1131 | compiled = compile(sourceFile.read(), sourcePath, 'exec') |
| 1132 | except SyntaxError: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 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 |
| 1139 | |
| 1140 | # Ok, we have a valid compilation. |
Guido van Rossum | f4ef7e6 | 1995-06-22 18:50:15 +0000 | [diff] [blame] | 1141 | try: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1142 | compiledFile.write(imp.get_magic()) # compiled magic number |
| 1143 | compiledFile.seek(8, 0) # mtime space holder |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 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() |
| 1149 | return compiledPath |
| 1150 | except IOError: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1151 | return None # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1152 | |
| 1153 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1154 | got_suffixes = None |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1155 | got_suffixes_dict = {} |
| 1156 | def get_suffixes(ty=None): |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1157 | """Produce a list of triples, each describing a type of import file. |
| 1158 | |
| 1159 | Triples have the form '(SUFFIX, MODE, TYPE)', where: |
| 1160 | |
| 1161 | SUFFIX is a string found appended to a module name to make a filename for |
| 1162 | that type of import file. |
| 1163 | |
| 1164 | MODE is the mode string to be passed to the built-in 'open' function - "r" |
| 1165 | for text files, "rb" for binary. |
| 1166 | |
| 1167 | TYPE is the file type: |
| 1168 | |
| 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. """ |
| 1174 | |
| 1175 | # Note: sorted_suffixes() depends on this function's value being invariant. |
| 1176 | # sorted_suffixes() must be revised if this becomes untrue. |
| 1177 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1178 | global got_suffixes, got_suffixes_dict |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1179 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1180 | if not got_suffixes: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1181 | # Ensure that the .pyc suffix precedes the .py: |
| 1182 | got_suffixes = [('', 'r', PY_PACKAGE)] |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1183 | got_suffixes_dict[PY_PACKAGE] = ('', 'r', PY_PACKAGE) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1184 | py = pyc = None |
| 1185 | for suff in imp.get_suffixes(): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1186 | got_suffixes_dict[suff[2]] = suff |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1187 | if suff[0] == '.py': |
| 1188 | py = suff |
| 1189 | elif suff[0] == '.pyc': |
| 1190 | pyc = suff |
| 1191 | else: |
| 1192 | got_suffixes.append(suff) |
| 1193 | got_suffixes.append(pyc) |
| 1194 | got_suffixes.append(py) |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1195 | if ty: |
| 1196 | return got_suffixes_dict[ty] # ==> |
| 1197 | else: |
| 1198 | return got_suffixes # ==> |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1199 | |
| 1200 | |
| 1201 | sortedSuffs = [] # State vars for sorted_suffixes(). Go |
| 1202 | def sorted_suffixes(): |
| 1203 | """Helper function ~efficiently~ tracks sorted list of module suffixes.""" |
| 1204 | |
| 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. |
| 1208 | |
| 1209 | global sortedsuffs |
| 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() |
| 1217 | return sortedSuffs |
| 1218 | |
| 1219 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1220 | def normalize_pathname(path): |
| 1221 | """Given PATHNAME, return an absolute pathname relative to cwd, reducing |
| 1222 | unnecessary components where convenient (eg, on Unix).""" |
| 1223 | |
| 1224 | # We do a lot more when we have posix-style paths, eg os.sep == '/'. |
| 1225 | |
| 1226 | if os.sep != '/': |
Guido van Rossum | 7f64e24 | 1995-07-12 15:34:34 +0000 | [diff] [blame^] | 1227 | return os.path.join(os.getcwd, path) # ==> |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1228 | |
| 1229 | outwards, inwards = 0, [] |
| 1230 | for nm in string.splitfields(path, os.sep): |
| 1231 | if nm != os.curdir: |
| 1232 | if nm == os.pardir: |
| 1233 | # Translate parent-dir entries to outward notches: |
| 1234 | if inwards: |
| 1235 | # Pop a containing inwards: |
| 1236 | del inwards[-1] |
| 1237 | else: |
| 1238 | # Register leading outward notches: |
| 1239 | outwards = outwards + 1 |
| 1240 | else: |
| 1241 | inwards.append(nm) |
| 1242 | inwards = string.joinfields(inwards, os.sep) |
| 1243 | |
| 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): |
| 1247 | cwd = os.getcwd() |
| 1248 | if outwards: |
| 1249 | cwd = string.splitfields(cwd, os.sep) |
| 1250 | cwd = string.joinfields(cwd[:len(cwd) - outwards], os.sep) |
| 1251 | if inwards: |
| 1252 | return os.path.join(cwd, inwards) # ==> |
| 1253 | else: |
| 1254 | return cwd # ==> |
| 1255 | else: |
| 1256 | return inwards # ==> |
| 1257 | |
| 1258 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 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. |
| 1263 | |
| 1264 | def exterior(): |
| 1265 | """Return dyad containing locals and globals of caller's caller. |
| 1266 | |
| 1267 | Locals will be None if same as globals, ie env is global env.""" |
| 1268 | |
| 1269 | bogus = 'bogus' # A locally usable exception |
| 1270 | try: raise bogus # Force an exception object |
| 1271 | except bogus: |
| 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? |
| 1276 | locals = None |
| 1277 | return (locals, globals) |
| 1278 | |
| 1279 | ######################################################################### |
| 1280 | # TESTING FACILITIES # |
| 1281 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1282 | def note(msg, threshold=2): |
Guido van Rossum | 96044da | 1995-04-07 09:06:50 +0000 | [diff] [blame] | 1283 | if VERBOSE >= threshold: sys.stderr.write('(import: ' + msg + ')\n') |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1284 | |
| 1285 | class TestDirHier: |
| 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...""" |
| 1289 | |
| 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 |
| 1293 | __del__ method).""" |
| 1294 | self.PKG_NM = 'tdh_' |
| 1295 | rev = 0 |
| 1296 | while os.path.exists(os.path.join(where, self.PKG_NM+str(rev))): |
| 1297 | rev = rev + 1 |
| 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) |
| 1302 | self.add(template) |
| 1303 | |
| 1304 | def __del__(self): |
| 1305 | """Cleanup the test hierarchy.""" |
| 1306 | self.remove() |
| 1307 | def add(self, template, root=None): |
| 1308 | """Populate directory according to template dictionary. |
| 1309 | |
| 1310 | Keys indicate file names, possibly directories themselves. |
| 1311 | |
| 1312 | String values dictate contents of flat files. |
| 1313 | |
| 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) |
| 1322 | self.add(val, name) |
| 1323 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1324 | raise ValueError, ('invalid file-value type, %s' % # ==X |
| 1325 | type(val)) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 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): |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1331 | print '(TestDirHier: eradicating %s)' % name |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1332 | os.system('rm -r ' + name) |
| 1333 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1334 | raise IOError, "can't remove non-existent " + name # ==X |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1335 | def createFile(self, name, contents=None): |
| 1336 | """Establish file NAME with CONTENTS. |
| 1337 | |
| 1338 | If no contents specfied, contents will be 'print NAME'.""" |
| 1339 | f = open(name, 'w') |
| 1340 | if not contents: |
| 1341 | f.write("print '" + name + "'\n") |
| 1342 | else: |
| 1343 | f.write(contents) |
| 1344 | f.close |
| 1345 | def createDir(self, name): |
| 1346 | """Create dir with NAME.""" |
| 1347 | return os.mkdir(name, 0755) |
| 1348 | |
| 1349 | skipToTest = 0 |
| 1350 | atTest = 1 |
| 1351 | def testExec(msg, execList, locals, globals): |
| 1352 | global skipToTest, atTest |
| 1353 | print 'Import Test:', '(' + str(atTest) + ')', msg, '...' |
| 1354 | atTest = atTest + 1 |
| 1355 | if skipToTest > (atTest - 1): |
| 1356 | print ' ... skipping til test', skipToTest |
| 1357 | return |
| 1358 | else: |
| 1359 | print '' |
| 1360 | for stmt in execList: |
| 1361 | exec stmt in locals, globals |
| 1362 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1363 | def test(number=0, leaveHiers=0): |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1364 | """Exercise import functionality, creating a transient dir hierarchy for |
| 1365 | the purpose. |
| 1366 | |
| 1367 | We actually install the new import functionality, temporarily, resuming the |
| 1368 | existing function on cleanup.""" |
| 1369 | |
| 1370 | import __builtin__ |
| 1371 | |
| 1372 | global skipToTest, atTest |
| 1373 | skipToTest = number |
| 1374 | hier = None |
| 1375 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1376 | def unloadFull(mod): |
| 1377 | """Unload module and offspring submodules, if any.""" |
| 1378 | modMod = '' |
| 1379 | if type(mod) == types.StringType: |
| 1380 | modNm = mod |
| 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: |
| 1385 | unload(subj) |
| 1386 | |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1387 | try: |
| 1388 | __main__.testMods |
| 1389 | except AttributeError: |
| 1390 | __main__.testMods = [] |
| 1391 | testMods = __main__.testMods |
| 1392 | |
| 1393 | |
| 1394 | # Install the newimp routines, within a try/finally: |
| 1395 | try: |
| 1396 | sys.exc_traceback = None |
| 1397 | wasImport = __builtin__.__import__ # Stash default |
| 1398 | wasPath = sys.path |
| 1399 | except AttributeError: |
| 1400 | wasImport = None |
| 1401 | try: |
| 1402 | hiers = []; modules = [] |
| 1403 | global VERBOSE |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1404 | wasVerbose, VERBOSE = VERBOSE, 1 |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1405 | __builtin__.__import__ = import_module # Install new version |
| 1406 | |
| 1407 | if testMods: # Clear out imports from previous tests |
| 1408 | for m in testMods[:]: |
| 1409 | unloadFull(m) |
| 1410 | testMods.remove(m) |
| 1411 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1412 | # ------ |
| 1413 | # Test 1 |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1414 | testExec("already imported module: %s" % sys.modules.keys()[0], |
| 1415 | ['import ' + sys.modules.keys()[0]], |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1416 | vars(), newimp_globals) |
| 1417 | no_sirree = 'no_sirree_does_not_exist' |
| 1418 | # ------ |
| 1419 | # Test 2 |
| 1420 | testExec("non-existent module: %s" % no_sirree, |
| 1421 | ['try: import ' + no_sirree + |
| 1422 | '\nexcept ImportError: pass'], |
| 1423 | vars(), newimp_globals) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1424 | got = None |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1425 | |
| 1426 | # ------ |
| 1427 | # Test 3 |
| 1428 | # Find a module that's not yet loaded, from a list of prospects: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1429 | for mod in ['Complex', 'UserDict', 'UserList', 'calendar', |
| 1430 | 'cmd', 'dis', 'mailbox', 'profile', 'random', 'rfc822']: |
| 1431 | if not (mod in sys.modules.keys()): |
| 1432 | got = mod |
| 1433 | break # ==v |
| 1434 | if got: |
| 1435 | testExec("not-yet loaded module: %s" % mod, |
| 1436 | ['import ' + mod, 'modules.append(got)'], |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1437 | vars(), newimp_globals) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1438 | else: |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1439 | testExec("not-yet loaded module: list exhausted, never mind", |
| 1440 | [], vars(), newimp_globals) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1441 | |
| 1442 | # Now some package stuff. |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1443 | |
| 1444 | # ------ |
| 1445 | # Test 4 |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 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)", |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1452 | "base = hier1.PKG_NM", |
| 1453 | "exec 'import ' + base", |
| 1454 | "testMods.append(base)"] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1455 | testExec("trivial package, with one module, a.py", |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1456 | stmts, vars(), newimp_globals) |
| 1457 | |
| 1458 | # ------ |
| 1459 | # Test 5 |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1460 | # Slightly less trivial package - reference to '__': |
| 1461 | stmts = [("hier2 = TestDirHier({'ref.py': 'print \"Pkg __:\", __'})"), |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1462 | "base = hier2.PKG_NM", |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1463 | "hiers.append(hier2)", |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1464 | "exec 'import ' + base", |
| 1465 | "testMods.append(base)"] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1466 | testExec("trivial package, with module that has pkg shorthand ref", |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1467 | stmts, vars(), newimp_globals) |
| 1468 | |
| 1469 | # ------ |
| 1470 | # Test 6 |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1471 | # Nested package, plus '__' references: |
| 1472 | |
| 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"""' % |
| 1478 | ('.../', |
| 1479 | ' ref.py\t\t\t"ref.py loading..."', |
| 1480 | ' suite/', |
| 1481 | ' s1.py \t\t"s1.py, in pkg: xxxx.suite"', |
| 1482 | ' subsuite/', |
| 1483 | ' sub1.py "sub1.py" ')), |
| 1484 | "hier3 = TestDirHier(complexTemplate)", |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1485 | "base = hier3.PKG_NM", |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1486 | "hiers.append(hier3)", |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1487 | "exec 'import ' + base", |
| 1488 | "testMods.append(base)"] |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1489 | testExec("Significantly nestled package:", |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1490 | stmts, vars(), newimp_globals) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1491 | |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1492 | # ------ |
| 1493 | # Test 7 |
| 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': |
| 1499 | {'prime': |
| 1500 | {'__init__.py': 'import __.easy, __.nother', |
| 1501 | 'easy.py': 'print "easy.py:", __name__', |
| 1502 | 'nother.py': ('%s\n%s\n%s\n' % |
| 1503 | ('import __.easy', |
| 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': |
| 1510 | 'awry': |
| 1511 | {'__init__.py': |
| 1512 | ('%s\n%s' % |
| 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) |
| 1528 | |
| 1529 | # ------ |
| 1530 | # test 8 |
| 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)", |
| 1540 | ("try: exec work" + |
| 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) |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1546 | |
| 1547 | sys.exc_traceback = None # Signify clean conclusion. |
| 1548 | |
| 1549 | finally: |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1550 | skipToTest = 0 |
| 1551 | atTest = 1 |
| 1552 | sys.path = wasPath |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1553 | VERBOSE = wasVerbose |
| 1554 | if wasImport: # Resurrect prior routine |
Guido van Rossum | 5232590 | 1995-04-07 09:03:10 +0000 | [diff] [blame] | 1555 | __builtin__.__import__ = wasImport |
| 1556 | else: |
| 1557 | del __builtin__.__import__ |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1558 | if leaveHiers: |
| 1559 | print 'Cleanup inhibited' |
| 1560 | else: |
| 1561 | if sys.exc_traceback: |
| 1562 | print ' ** Import test FAILURE... cleanup.' |
| 1563 | else: |
| 1564 | print ' Import test SUCCESS... cleanup' |
| 1565 | for h in hiers: h.remove(); del h # Dispose of test directories |
| 1566 | |
| 1567 | init() |
Guido van Rossum | fa486a2 | 1995-04-07 09:04:01 +0000 | [diff] [blame] | 1568 | |
| 1569 | if __name__ == '__main__': |
Guido van Rossum | b89ab8c | 1995-07-12 02:17:51 +0000 | [diff] [blame] | 1570 | test() |