~ubuntu-branches/debian/squeeze/nose/squeeze

« back to all changes in this revision

Viewing changes to nose/importer.py

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Marek, Torsten Marek, Gustavo Noronha Silva
  • Date: 2008-06-12 13:39:43 UTC
  • mfrom: (1.2.1 upstream) (2.1.5 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080612133943-2q7syp67fwl4on13
Tags: 0.10.3-1

[Torsten Marek]
* New upstream release (Closes: #461994)
* debian/control
  - bump standards version to 3.8.0, no changes necessary
  - add suggestions for python-coverage (Closes: #457053)
  - change dependency on python-setuptools into 
    python-pkg-resources (Closes: #468719)
  - added myself to uploaders

[Gustavo Noronha Silva]
* debian/control:
  - remove -1 from build-dep on setuptools

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
import logging
8
8
import os
9
9
import sys
 
10
from nose.config import Config
 
11
 
10
12
from imp import find_module, load_module, acquire_lock, release_lock
11
13
 
12
14
log = logging.getLogger(__name__)
13
 
_modules = {}
14
 
 
15
 
def add_path(path):
16
 
    """Ensure that the path, or the root of the current package (if
17
 
    path is in a package) is in sys.path.
18
 
    """
19
 
    log.debug('Add path %s' % path)
20
 
    if not path:
21
 
        return
22
 
    parent = os.path.dirname(path)
23
 
    if (parent
24
 
        and os.path.exists(os.path.join(path, '__init__.py'))):
25
 
        add_path(parent)
26
 
    elif not path in sys.path:
27
 
        log.debug("insert %s into sys.path", path)
28
 
        sys.path.insert(0, path)
29
 
        
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.
33
 
    """
34
 
    log.debug("Import %s from %s (addpaths: %s)", name, path, conf.addPaths)
35
 
    
36
 
    # special case for __main__
37
 
    if name == '__main__':
38
 
        return sys.modules[name]
39
 
 
40
 
    # make sure we're doing an absolute import
41
 
    # name, path = make_absolute(name, path)
42
 
    
43
 
    if conf.addPaths:
44
 
        for p in path:
45
 
            add_path(p)
46
 
 
47
 
    path = [ p for p in path if p is not None ]
48
 
    cache = _modules.setdefault(':'.join(path), {})
49
 
 
50
 
    # quick exit for fully cached names
51
 
    if cache.has_key(name):
52
 
        return cache[name]
53
 
    
54
 
    parts = name.split('.')
55
 
    fqname = ''
56
 
    mod = parent = fh = None
57
 
    
58
 
    for part in parts:
59
 
        if fqname == '':
60
 
            fqname = part
61
 
        else:
62
 
            fqname = "%s.%s" % (fqname, part)
63
 
 
64
 
        if cache.has_key(fqname):
65
 
            mod = cache[fqname]
66
 
        else:
 
15
 
 
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.
 
20
    """
 
21
    def __init__(self, config=None):
 
22
        if config is None:
 
23
            config = Config()
 
24
        self.config = config
 
25
 
 
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.
 
30
        """
 
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__'):
 
35
            path_parts.pop()
 
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)                
 
40
 
 
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.
 
44
        """
 
45
        dir = os.path.normpath(os.path.abspath(dir))
 
46
        log.debug("Import %s from %s", fqname, dir)
 
47
 
 
48
        # FIXME reimplement local per-dir cache?
 
49
        
 
50
        # special case for __main__
 
51
        if fqname == '__main__':
 
52
            return sys.modules[fqname]
 
53
        
 
54
        if self.config.addPaths:
 
55
            add_path(dir, self.config)
 
56
            
 
57
        path = [dir]
 
58
        parts = fqname.split('.')
 
59
        part_fqname = ''
 
60
        mod = parent = fh = None
 
61
 
 
62
        for part in parts:
 
63
            if part_fqname == '':
 
64
                part_fqname = part
 
65
            else:
 
66
                part_fqname = "%s.%s" % (part_fqname, part)
67
67
            try:
68
68
                acquire_lock()
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
 
                if old:
 
72
                old = sys.modules.get(part_fqname)
 
73
                if old is not None:
73
74
                    # test modules frequently have name overlap; make sure
74
75
                    # we get a fresh copy of anything we are trying to load
75
76
                    # from a new path
76
 
                    if hasattr(old,'__path__'):
77
 
                        old_path = os.path.normpath(old.__path__[0])
78
 
                        old_ext = None
79
 
                    elif hasattr(old, '__file__'):
80
 
                        old_norm = os.path.normpath(old.__file__)
81
 
                        old_path, old_ext = os.path.splitext(old_norm)
82
 
                    else:
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
93
 
                        continue
94
 
                    else:
95
 
                        del sys.modules[fqname]
96
 
                mod = load_module(fqname, fh, filename, desc)
97
 
                cache[fqname] = mod
 
77
                    log.debug("sys.modules has %s as %s", part_fqname, old)
 
78
                    if self.sameModule(old, filename):
 
79
                        mod = old
 
80
                    else:
 
81
                        del sys.modules[part_fqname]
 
82
                        mod = load_module(part_fqname, fh, filename, desc)
 
83
                else:
 
84
                    mod = load_module(part_fqname, fh, filename, desc)
98
85
            finally:
99
86
                if fh:
100
87
                    fh.close()
101
88
                release_lock()
102
 
        if parent:
103
 
            setattr(parent, part, mod)
 
89
            if parent:
 
90
                setattr(parent, part, mod)
 
91
            if hasattr(mod, '__path__'):
 
92
                path = mod.__path__
 
93
            parent = mod
 
94
        return mod
 
95
 
 
96
    def sameModule(self, mod, filename):
 
97
        mod_paths = []
104
98
        if hasattr(mod, '__path__'):
105
 
            path = mod.__path__
106
 
        parent = mod
107
 
    return mod
108
 
 
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(
 
101
                    os.path.normpath(
 
102
                    os.path.abspath(path))))
 
103
        elif hasattr(mod, '__file__'):
 
104
            mod_paths.append(os.path.dirname(
 
105
                os.path.normpath(
 
106
                os.path.abspath(mod.__file__))))
 
107
        else:
 
108
            # builtin or other module-like object that
 
109
            # doesn't have __file__; must be new
 
110
            return False
 
111
        new_path = os.path.dirname(os.path.normpath(filename))
 
112
        for mod_path in mod_paths:
 
113
            log.debug(
 
114
                "module already loaded? mod: %s new: %s",
 
115
                mod_path, new_path)
 
116
            if mod_path == new_path:
 
117
                return True
 
118
        return False
 
119
 
 
120
 
 
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.
113
124
    """
114
 
    if not os.path.exists(os.path.join(path, '__init__.py')):
115
 
        return (name, path)
116
 
    path, parent = os.path.split(path)
117
 
    name = "%s.%s" % (parent, path)
118
 
    return make_absolute(name, path)
 
125
 
 
126
    # FIXME add any src-looking dirs seen too... need to get config for that
 
127
    
 
128
    log.debug('Add path %s' % path)    
 
129
    if not path:
 
130
        return []
 
131
    added = []
 
132
    parent = os.path.dirname(path)
 
133
    if (parent
 
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)
 
139
        added.append(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)
 
146
    return added
 
147
 
 
148
 
 
149
def remove_path(path):
 
150
    log.debug('Remove path %s' % path)
 
151
    if path in sys.path:
 
152
        sys.path.remove(path)