10
from nose.config import Config
10
12
from imp import find_module, load_module, acquire_lock, release_lock
12
14
log = logging.getLogger(__name__)
16
"""Ensure that the path, or the root of the current package (if
17
path is in a package) is in sys.path.
19
log.debug('Add path %s' % path)
22
parent = os.path.dirname(path)
24
and os.path.exists(os.path.join(path, '__init__.py'))):
26
elif not path in sys.path:
27
log.debug("insert %s into sys.path", path)
28
sys.path.insert(0, path)
30
def _import(name, path, conf):
31
"""Import a module *only* from path, ignoring sys.path and
32
reloading if the version in sys.modules is not the one we want.
34
log.debug("Import %s from %s (addpaths: %s)", name, path, conf.addPaths)
36
# special case for __main__
37
if name == '__main__':
38
return sys.modules[name]
40
# make sure we're doing an absolute import
41
# name, path = make_absolute(name, path)
47
path = [ p for p in path if p is not None ]
48
cache = _modules.setdefault(':'.join(path), {})
50
# quick exit for fully cached names
51
if cache.has_key(name):
54
parts = name.split('.')
56
mod = parent = fh = None
62
fqname = "%s.%s" % (fqname, part)
64
if cache.has_key(fqname):
16
class Importer(object):
17
"""An importer class that does only path-specific imports. That
18
is, the given module is not searched for on sys.path, but only at
19
the path or in the directory specified.
21
def __init__(self, config=None):
26
def importFromPath(self, path, fqname):
27
"""Import a dotted-name package whose tail is at path. In other words,
28
given foo.bar and path/to/foo/bar.py, import foo from path/to/foo then
29
bar from path/to/foo/bar, returning bar.
31
# find the base dir of the package
32
path_parts = os.path.normpath(os.path.abspath(path)).split(os.sep)
33
name_parts = fqname.split('.')
34
if path_parts[-1].startswith('__init__'):
36
path_parts = path_parts[:-(len(name_parts))]
37
dir_path = os.sep.join(path_parts)
38
# then import fqname starting from that dir
39
return self.importFromDir(dir_path, fqname)
41
def importFromDir(self, dir, fqname):
42
"""Import a module *only* from path, ignoring sys.path and
43
reloading if the version in sys.modules is not the one we want.
45
dir = os.path.normpath(os.path.abspath(dir))
46
log.debug("Import %s from %s", fqname, dir)
48
# FIXME reimplement local per-dir cache?
50
# special case for __main__
51
if fqname == '__main__':
52
return sys.modules[fqname]
54
if self.config.addPaths:
55
add_path(dir, self.config)
58
parts = fqname.split('.')
60
mod = parent = fh = None
66
part_fqname = "%s.%s" % (part_fqname, part)
69
log.debug("find module part %s (%s) at %s", part, fqname, path)
69
log.debug("find module part %s (%s) in %s",
70
part, part_fqname, path)
70
71
fh, filename, desc = find_module(part, path)
71
old = sys.modules.get(fqname)
72
old = sys.modules.get(part_fqname)
73
74
# test modules frequently have name overlap; make sure
74
75
# we get a fresh copy of anything we are trying to load
76
if hasattr(old,'__path__'):
77
old_path = os.path.normpath(old.__path__[0])
79
elif hasattr(old, '__file__'):
80
old_norm = os.path.normpath(old.__file__)
81
old_path, old_ext = os.path.splitext(old_norm)
83
# builtin or other module-like object that
84
# doesn't have __file__
85
old_path, old_ext, old_norm = None, None, None
86
new_norm = os.path.normpath(filename)
87
new_path, new_ext = os.path.splitext(new_norm)
88
if old_path == new_path:
89
log.debug("module %s already loaded "
90
"old: %s %s new: %s %s", fqname, old_path,
91
old_ext, new_path, new_ext)
92
cache[fqname] = mod = old
95
del sys.modules[fqname]
96
mod = load_module(fqname, fh, filename, desc)
77
log.debug("sys.modules has %s as %s", part_fqname, old)
78
if self.sameModule(old, filename):
81
del sys.modules[part_fqname]
82
mod = load_module(part_fqname, fh, filename, desc)
84
mod = load_module(part_fqname, fh, filename, desc)
103
setattr(parent, part, mod)
90
setattr(parent, part, mod)
91
if hasattr(mod, '__path__'):
96
def sameModule(self, mod, filename):
104
98
if hasattr(mod, '__path__'):
109
def make_absolute(name, path):
110
"""Given a module name and the path at which it is found, back up to find
111
the parent of the module, popping directories off of the path so long as
112
they contain __init__.py files.
99
for path in mod.__path__:
100
mod_paths.append(os.path.dirname(
102
os.path.abspath(path))))
103
elif hasattr(mod, '__file__'):
104
mod_paths.append(os.path.dirname(
106
os.path.abspath(mod.__file__))))
108
# builtin or other module-like object that
109
# doesn't have __file__; must be new
111
new_path = os.path.dirname(os.path.normpath(filename))
112
for mod_path in mod_paths:
114
"module already loaded? mod: %s new: %s",
116
if mod_path == new_path:
121
def add_path(path, config=None):
122
"""Ensure that the path, or the root of the current package (if
123
path is in a package) is in sys.path.
114
if not os.path.exists(os.path.join(path, '__init__.py')):
116
path, parent = os.path.split(path)
117
name = "%s.%s" % (parent, path)
118
return make_absolute(name, path)
126
# FIXME add any src-looking dirs seen too... need to get config for that
128
log.debug('Add path %s' % path)
132
parent = os.path.dirname(path)
134
and os.path.exists(os.path.join(path, '__init__.py'))):
135
added.extend(add_path(parent, config))
136
elif not path in sys.path:
137
log.debug("insert %s into sys.path", path)
138
sys.path.insert(0, path)
140
if config and config.srcDirs:
141
for dirname in config.srcDirs:
142
dirpath = os.path.join(path, dirname)
143
if os.path.isdir(dirpath):
144
sys.path.insert(0, dirpath)
145
added.append(dirpath)
149
def remove_path(path):
150
log.debug('Remove path %s' % path)
152
sys.path.remove(path)