~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lazy_import.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-07-19 16:09:34 UTC
  • mfrom: (2520.4.135 bzr.mpbundle)
  • Revision ID: pqm@pqm.ubuntu.com-20070719160934-d51fyijw69oto88p
Add new bundle and merge-directive formats

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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::
23
 
 
 
22
in an on-demand fashion. Typically use looks like:
24
23
    from bzrlib.lazy_import import lazy_import
25
24
    lazy_import(globals(), '''
26
25
    from bzrlib import (
31
30
    import bzrlib.branch
32
31
    ''')
33
32
 
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.
 
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.
36
35
 
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).
 
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).
42
41
"""
43
42
 
44
 
from __future__ import absolute_import
45
 
 
46
43
 
47
44
class ScopeReplacer(object):
48
45
    """A lazy object that will replace itself in the appropriate scope.
67
64
            It will be passed (self, scope, name)
68
65
        :param name: The variable name in the given scope.
69
66
        """
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)
 
67
        self._scope = scope
 
68
        self._factory = factory
 
69
        self._name = name
 
70
        self._real_obj = None
74
71
        scope[name] = self
75
72
 
76
73
    def _replace(self):
90
87
                          " to another variable?",
91
88
                extra=e)
92
89
        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.")
96
90
        if ScopeReplacer._should_proxy:
97
 
            object.__setattr__(self, '_real_obj', obj)
 
91
            self._real_obj = obj
98
92
        scope[name] = obj
99
93
        return obj
100
94
 
101
95
    def _cleanup(self):
102
96
        """Stop holding on to all the extra stuff"""
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
 
 
 
97
        del self._factory
 
98
        del self._scope
116
99
        # We keep _name, so that we can report errors
117
100
        # del self._name
118
101
 
125
108
            _cleanup()
126
109
        return getattr(obj, attr)
127
110
 
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
 
 
137
111
    def __call__(self, *args, **kwargs):
138
112
        _replace = object.__getattribute__(self, '_replace')
139
113
        obj = _replace()
166
140
 
167
141
        :param scope: The scope that objects should be imported into.
168
142
            Typically this is globals()
169
 
        :param name: The variable name. Often this is the same as the
 
143
        :param name: The variable name. Often this is the same as the 
170
144
            module_path. 'bzrlib'
171
145
        :param module_path: A list for the fully specified module path
172
146
            ['bzrlib', 'foo', 'bar']
174
148
            None, indicating the module is being imported.
175
149
        :param children: Children entries to be imported later.
176
150
            This should be a map of children specifications.
177
 
            ::
178
 
            
179
 
                {'foo':(['bzrlib', 'foo'], None,
180
 
                    {'bar':(['bzrlib', 'foo', 'bar'], None {})})
181
 
                }
182
 
 
183
 
        Examples::
184
 
 
 
151
            {'foo':(['bzrlib', 'foo'], None, 
 
152
                {'bar':(['bzrlib', 'foo', 'bar'], None {})})
 
153
            }
 
154
        Examples:
185
155
            import foo => name='foo' module_path='foo',
186
156
                          member=None, children={}
187
157
            import foo.bar => name='foo' module_path='foo', member=None,
191
161
            from foo import bar, baz would get translated into 2 import
192
162
            requests. On for 'name=bar' and one for 'name=baz'
193
163
        """
194
 
        if (member is not None) and children:
195
 
            raise ValueError('Cannot supply both a member and children')
 
164
        if member is not None:
 
165
            assert not children, \
 
166
                'Cannot supply both a member and children'
196
167
 
197
 
        object.__setattr__(self, '_import_replacer_children', children)
198
 
        object.__setattr__(self, '_member', member)
199
 
        object.__setattr__(self, '_module_path', module_path)
 
168
        self._import_replacer_children = children
 
169
        self._member = member
 
170
        self._module_path = module_path
200
171
 
201
172
        # Indirecting through __class__ so that children can
202
173
        # override _import (especially our instrumented version)
280
251
 
281
252
        :param import_str: The import string to process
282
253
        """
283
 
        if not import_str.startswith('import '):
284
 
            raise ValueError('bad import string %r' % (import_str,))
 
254
        assert import_str.startswith('import ')
285
255
        import_str = import_str[len('import '):]
286
256
 
287
257
        for path in import_str.split(','):
326
296
 
327
297
        :param from_str: The import string to process
328
298
        """
329
 
        if not from_str.startswith('from '):
330
 
            raise ValueError('bad from/import %r' % from_str)
 
299
        assert from_str.startswith('from ')
331
300
        from_str = from_str[len('from '):]
332
301
 
333
302
        from_module, import_list = from_str.split(' import ')
388
357
def lazy_import(scope, text, lazy_import_class=None):
389
358
    """Create lazy imports for all of the imports in text.
390
359
 
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
 
        ''')
 
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
    ''')
403
371
 
404
372
    Then 'foo, bar, baz' and 'bzrlib' will exist as lazy-loaded
405
373
    objects which will be replaced with a real object on first use.