~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lazy_import.py

(jelmer) Remove config argument from VersionedFileRepository.add_revision()
 (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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Functionality to create lazy evaluation objects.
18
18
 
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.
64
67
            It will be passed (self, scope, name)
65
68
        :param name: The variable name in the given scope.
66
69
        """
67
 
        self._scope = scope
68
 
        self._factory = factory
69
 
        self._name = name
70
 
        self._real_obj = None
 
70
        object.__setattr__(self, '_scope', scope)
 
71
        object.__setattr__(self, '_factory', factory)
 
72
        object.__setattr__(self, '_name', name)
 
73
        object.__setattr__(self, '_real_obj', None)
71
74
        scope[name] = self
72
75
 
73
76
    def _replace(self):
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
 
            self._real_obj = obj
 
97
            object.__setattr__(self, '_real_obj', obj)
92
98
        scope[name] = obj
93
99
        return 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
 
108
125
            _cleanup()
109
126
        return getattr(obj, attr)
110
127
 
 
128
    def __setattr__(self, attr, value):
 
129
        obj = object.__getattribute__(self, '_real_obj')
 
130
        if obj is None:
 
131
            _replace = object.__getattribute__(self, '_replace')
 
132
            obj = _replace()
 
133
            _cleanup = object.__getattribute__(self, '_cleanup')
 
134
            _cleanup()
 
135
        return setattr(obj, attr, value)
 
136
 
111
137
    def __call__(self, *args, **kwargs):
112
138
        _replace = object.__getattribute__(self, '_replace')
113
139
        obj = _replace()
140
166
 
141
167
        :param scope: The scope that objects should be imported into.
142
168
            Typically this is globals()
143
 
        :param name: The variable name. Often this is the same as the 
 
169
        :param name: The variable name. Often this is the same as the
144
170
            module_path. 'bzrlib'
145
171
        :param module_path: A list for the fully specified module path
146
172
            ['bzrlib', 'foo', 'bar']
148
174
            None, indicating the module is being imported.
149
175
        :param children: Children entries to be imported later.
150
176
            This should be a map of children specifications.
151
 
            {'foo':(['bzrlib', 'foo'], None, 
152
 
                {'bar':(['bzrlib', 'foo', 'bar'], None {})})
153
 
            }
154
 
        Examples:
 
177
            ::
 
178
            
 
179
                {'foo':(['bzrlib', 'foo'], None,
 
180
                    {'bar':(['bzrlib', 'foo', 'bar'], None {})})
 
181
                }
 
182
 
 
183
        Examples::
 
184
 
155
185
            import foo => name='foo' module_path='foo',
156
186
                          member=None, children={}
157
187
            import foo.bar => name='foo' module_path='foo', member=None,
161
191
            from foo import bar, baz would get translated into 2 import
162
192
            requests. On for 'name=bar' and one for 'name=baz'
163
193
        """
164
 
        if member is not None:
165
 
            assert not children, \
166
 
                'Cannot supply both a member and children'
 
194
        if (member is not None) and children:
 
195
            raise ValueError('Cannot supply both a member and children')
167
196
 
168
 
        self._import_replacer_children = children
169
 
        self._member = member
170
 
        self._module_path = module_path
 
197
        object.__setattr__(self, '_import_replacer_children', children)
 
198
        object.__setattr__(self, '_member', member)
 
199
        object.__setattr__(self, '_module_path', module_path)
171
200
 
172
201
        # Indirecting through __class__ so that children can
173
202
        # override _import (especially our instrumented version)
181
210
        module_path = object.__getattribute__(self, '_module_path')
182
211
        module_python_path = '.'.join(module_path)
183
212
        if member is not None:
184
 
            module = __import__(module_python_path, scope, scope, [member])
 
213
            module = __import__(module_python_path, scope, scope, [member], level=0)
185
214
            return getattr(module, member)
186
215
        else:
187
 
            module = __import__(module_python_path, scope, scope, [])
 
216
            module = __import__(module_python_path, scope, scope, [], level=0)
188
217
            for path in module_path[1:]:
189
218
                module = getattr(module, path)
190
219
 
251
280
 
252
281
        :param import_str: The import string to process
253
282
        """
254
 
        assert import_str.startswith('import ')
 
283
        if not import_str.startswith('import '):
 
284
            raise ValueError('bad import string %r' % (import_str,))
255
285
        import_str = import_str[len('import '):]
256
286
 
257
287
        for path in import_str.split(','):
296
326
 
297
327
        :param from_str: The import string to process
298
328
        """
299
 
        assert from_str.startswith('from ')
 
329
        if not from_str.startswith('from '):
 
330
            raise ValueError('bad from/import %r' % from_str)
300
331
        from_str = from_str[len('from '):]
301
332
 
302
333
        from_module, import_list = from_str.split(' import ')
357
388
def lazy_import(scope, text, lazy_import_class=None):
358
389
    """Create lazy imports for all of the imports in text.
359
390
 
360
 
    This is typically used as something like:
361
 
    from bzrlib.lazy_import import lazy_import
362
 
    lazy_import(globals(), '''
363
 
    from bzrlib import (
364
 
        foo,
365
 
        bar,
366
 
        baz,
367
 
        )
368
 
    import bzrlib.branch
369
 
    import bzrlib.transport
370
 
    ''')
 
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
        ''')
371
403
 
372
404
    Then 'foo, bar, baz' and 'bzrlib' will exist as lazy-loaded
373
405
    objects which will be replaced with a real object on first use.