public
Last active

knee.py for Python 2.6, 2.7, and 3.2

  • Download Gist
knee.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
"""
An Python re-implementation of hierarchical module import.
 
Function names and arguments have been chosen to mimic the C code in
`Python/import.c` whenever possible.
 
This code is intended to be read, not executed. However, it does work
-- all you need to do to enable it is "import knee".
 
(The name is a pun on the klunkier predecessor of this module, "ni".)
 
"""
 
import __builtin__
import imp
import sys
 
from types import ModuleType
from warnings import warn
 
def get_parent(globals, level):
"""
parent, name = get_parent(globals, level)
 
Return the package that an import is being performed in. If globals comes
from the module foo.bar.bat (not itself a package), this returns the
sys.modules entry for foo.bar. If globals is from a package's __init__.py,
the package's entry in sys.modules is returned.
 
If globals doesn't come from a package or a module in a package, or a
corresponding entry is not found in sys.modules, None is returned.
"""
orig_level = level
 
if not level or not isinstance(globals, dict):
return None, ''
 
pkgname = globals.get('__package__', None)
 
if pkgname is not None:
# __package__ is set, so use it
if not hasattr(pkgname, 'rindex'):
raise ValueError('__package__ set to non-string')
if len(pkgname) == 0:
if level > 0:
raise ValueError('Attempted relative import in non-package')
return None, ''
name = pkgname
else:
# __package__ not set, so figure it out and set it
if '__name__' not in globals:
return None, ''
modname = globals['__name__']
 
if '__path__' in globals:
# __path__ is set, so modname is already the package name
globals['__package__'] = name = modname
else:
# Normal module, so work out the package name if any
lastdot = modname.rfind('.')
if lastdot < 0 and level > 0:
raise ValueError("Attempted relative import in non-package")
if lastdot < 0:
globals['__package__'] = None
return None, ''
globals['__package__'] = name = modname[:lastdot]
 
dot = len(name)
for x in xrange(level, 1, -1):
try:
dot = name.rindex('.', 0, dot)
except ValueError:
raise ValueError("attempted relative import beyond top-level "
"package")
name = name[:dot]
 
try:
parent = sys.modules[name]
except:
if orig_level < 1:
warn("Parent module '%.200s' not found while handling absolute "
"import" % name)
parent = None
else:
raise SystemError("Parent module '%.200s' not loaded, cannot "
"perform relative import" % name)
 
# We expect, but can't guarantee, if parent != None, that:
# - parent.__name__ == name
# - parent.__dict__ is globals
# If this is violated... Who cares?
return parent, name
 
def load_next(mod, altmod, name, buf):
"""
mod, name, buf = load_next(mod, altmod, name, buf)
 
altmod is either None or same as mod
"""
 
if len(name) == 0:
# completely empty module name should only happen in
# 'from . import' (or '__import__("")')
return mod, None, buf
 
dot = name.find('.')
if dot == 0:
raise ValueError('Empty module name')
 
if dot < 0:
subname = name
next = None
else:
subname = name[:dot]
next = name[dot+1:]
 
if buf != '':
buf += '.'
buf += subname
 
result = import_submodule(mod, subname, buf)
if result is None and mod != altmod:
result = import_submodule(altmod, subname, subname)
if result is not None:
buf = subname
 
if result is None:
raise ImportError("No module named %.200s" % name)
 
return result, next, buf
 
def import_submodule(mod, subname, fullname):
"""m = import_submodule(mod, subname, fullname)"""
# Require:
# if mod == None: subname == fullname
# else: mod.__name__ + "." + subname == fullname
 
if fullname in sys.modules:
m = sys.modules[fullname]
else:
if mod is None:
path = None
elif hasattr(mod, '__path__'):
path = mod.__path__
else:
return None
 
try:
fp, filename, stuff = imp.find_module(subname, path)
except ImportError:
return None
 
try:
m = imp.load_module(fullname, fp, filename, stuff)
finally:
if fp: fp.close()
 
add_submodule(mod, m, fullname, subname)
 
return m
 
def add_submodule(mod, submod, fullname, subname):
"""mod.{subname} = submod"""
if mod is None:
return #Nothing to do here.
 
if submod is None:
submod = sys.modules[fullname]
 
setattr(mod, subname, submod)
 
return
 
def ensure_fromlist(mod, fromlist, buf, recursive):
"""Handle 'from module import a, b, c' imports."""
if not hasattr(mod, '__path__'):
return
for item in fromlist:
if not hasattr(item, 'rindex'):
raise TypeError("Item in ``from list'' not a string")
if item == '*':
if recursive:
continue # avoid endless recursion
try:
all = mod.__all__
except AttributeError:
pass
else:
ret = ensure_fromlist(mod, all, buf, 1)
if not ret:
return 0
elif not hasattr(mod, item):
import_submodule(mod, item, buf + '.' + item)
 
def import_module_level(name, globals=None, locals=None, fromlist=None, level=-1):
"""Replacement for __import__()"""
parent, buf = get_parent(globals, level)
 
head, name, buf = load_next(parent, None if level < 0 else parent, name, buf)
 
tail = head
while name:
tail, name, buf = load_next(tail, tail, name, buf)
 
# If tail is None, both get_parent and load_next found
# an empty module name: someone called __import__("") or
# doctored faulty bytecode
if tail is None:
raise ValueError('Empty module name')
 
if not fromlist:
return head
 
ensure_fromlist(tail, fromlist, buf, 0)
return tail
 
modules_reloading = {}
 
def reload_module(m):
"""Replacement for reload()."""
if not isinstance(m, ModuleType):
raise TypeError("reload() argument must be module")
 
name = m.__name__
 
if name not in sys.modules:
raise ImportError("reload(): module %.200s not in sys.modules" % name)
 
global modules_reloading
try:
return modules_reloading[name]
except:
modules_reloading[name] = m
 
dot = name.rfind('.')
if dot < 0:
subname = name
path = None
else:
try:
parent = sys.modules[name[:dot]]
except KeyError:
modules_reloading.clear()
raise ImportError("reload(): parent %.200s not in sys.modules" % name[:dot])
subname = name[dot+1:]
path = getattr(parent, "__path__", None)
 
try:
fp, filename, stuff = imp.find_module(subname, path)
finally:
modules_reloading.clear()
 
try:
newm = imp.load_module(name, fp, filename, stuff)
except:
# load_module probably removed name from modules because of
# the error. Put back the original module object.
sys.modules[name] = m
raise
finally:
if fp: fp.close()
 
modules_reloading.clear()
return newm
 
# Save the original hooks
original_import = __builtin__.__import__
try:
original_reload = __builtin__.reload
except AttributeError:
original_reload = imp.reload # Python 3
 
__builtin__.__import__ = import_module_level
__builtin__.reload = reload_module

See also importlib -- "An implementation of import" -- which is provided in Python 3.1 and later.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.