~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lazy_import.py

(jelmer) Use the absolute_import feature everywhere in bzrlib,
 and add a source test to make sure it's used everywhere. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
19
19
This includes waiting to import a module until it is actually used.
20
20
 
21
21
Most commonly, the 'lazy_import' function is used to import other modules
22
 
in an on-demand fashion. Typically use looks like:
 
22
in an on-demand fashion. Typically use looks like::
 
23
 
23
24
    from bzrlib.lazy_import import lazy_import
24
25
    lazy_import(globals(), '''
25
26
    from bzrlib import (
30
31
    import bzrlib.branch
31
32
    ''')
32
33
 
33
 
    Then 'errors, osutils, branch' and 'bzrlib' will exist as lazy-loaded
34
 
    objects which will be replaced with a real object on first use.
 
34
Then 'errors, osutils, branch' and 'bzrlib' will exist as lazy-loaded
 
35
objects which will be replaced with a real object on first use.
35
36
 
36
 
    In general, it is best to only load modules in this way. This is because
37
 
    it isn't safe to pass these variables to other functions before they
38
 
    have been replaced. This is especially true for constants, sometimes
39
 
    true for classes or functions (when used as a factory, or you want
40
 
    to inherit from them).
 
37
In general, it is best to only load modules in this way. This is because
 
38
it isn't safe to pass these variables to other functions before they
 
39
have been replaced. This is especially true for constants, sometimes
 
40
true for classes or functions (when used as a factory, or you want
 
41
to inherit from them).
41
42
"""
42
43
 
 
44
from __future__ import absolute_import
 
45
 
43
46
 
44
47
class ScopeReplacer(object):
45
48
    """A lazy object that will replace itself in the appropriate scope.
87
90
                          " to another variable?",
88
91
                extra=e)
89
92
        obj = factory(self, scope, name)
 
93
        if obj is self:
 
94
            raise errors.IllegalUseOfScopeReplacer(name, msg="Object tried"
 
95
                " to replace itself, check it's not using its own scope.")
90
96
        if ScopeReplacer._should_proxy:
91
97
            object.__setattr__(self, '_real_obj', obj)
92
98
        scope[name] = obj
94
100
 
95
101
    def _cleanup(self):
96
102
        """Stop holding on to all the extra stuff"""
97
 
        del self._factory
98
 
        del self._scope
 
103
        try:
 
104
            del self._factory
 
105
        except AttributeError:
 
106
            # Oops, we just lost a race with another caller of _cleanup.  Just
 
107
            # ignore it.
 
108
            pass
 
109
 
 
110
        try:
 
111
            del self._scope
 
112
        except AttributeError:
 
113
            # Another race loss.  See above.
 
114
            pass
 
115
 
99
116
        # We keep _name, so that we can report errors
100
117
        # del self._name
101
118
 
157
174
            None, indicating the module is being imported.
158
175
        :param children: Children entries to be imported later.
159
176
            This should be a map of children specifications.
160
 
            {'foo':(['bzrlib', 'foo'], None,
161
 
                {'bar':(['bzrlib', 'foo', 'bar'], None {})})
162
 
            }
163
 
        Examples:
 
177
            ::
 
178
            
 
179
                {'foo':(['bzrlib', 'foo'], None,
 
180
                    {'bar':(['bzrlib', 'foo', 'bar'], None {})})
 
181
                }
 
182
 
 
183
        Examples::
 
184
 
164
185
            import foo => name='foo' module_path='foo',
165
186
                          member=None, children={}
166
187
            import foo.bar => name='foo' module_path='foo', member=None,
189
210
        module_path = object.__getattribute__(self, '_module_path')
190
211
        module_python_path = '.'.join(module_path)
191
212
        if member is not None:
192
 
            module = __import__(module_python_path, scope, scope, [member])
 
213
            module = __import__(module_python_path, scope, scope, [member], level=0)
193
214
            return getattr(module, member)
194
215
        else:
195
 
            module = __import__(module_python_path, scope, scope, [])
 
216
            module = __import__(module_python_path, scope, scope, [], level=0)
196
217
            for path in module_path[1:]:
197
218
                module = getattr(module, path)
198
219
 
367
388
def lazy_import(scope, text, lazy_import_class=None):
368
389
    """Create lazy imports for all of the imports in text.
369
390
 
370
 
    This is typically used as something like:
371
 
    from bzrlib.lazy_import import lazy_import
372
 
    lazy_import(globals(), '''
373
 
    from bzrlib import (
374
 
        foo,
375
 
        bar,
376
 
        baz,
377
 
        )
378
 
    import bzrlib.branch
379
 
    import bzrlib.transport
380
 
    ''')
 
391
    This is typically used as something like::
 
392
 
 
393
        from bzrlib.lazy_import import lazy_import
 
394
        lazy_import(globals(), '''
 
395
        from bzrlib import (
 
396
            foo,
 
397
            bar,
 
398
            baz,
 
399
            )
 
400
        import bzrlib.branch
 
401
        import bzrlib.transport
 
402
        ''')
381
403
 
382
404
    Then 'foo, bar, baz' and 'bzrlib' will exist as lazy-loaded
383
405
    objects which will be replaced with a real object on first use.