~bzr-pqm/bzr/bzr.dev

5387.2.7 by John Arbash Meinel
Merge bzr.dev 5444 to resolve some small text conflicts.
1
# Copyright (C) 2006-2010 Canonical Ltd
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
16
17
"""Functionality to create lazy evaluation objects.
18
19
This includes waiting to import a module until it is actually used.
1996.1.26 by John Arbash Meinel
Update HACKING and docstrings
20
21
Most commonly, the 'lazy_import' function is used to import other modules
5891.1.2 by Andrew Bennetts
Fix a bunch of docstring formatting nits, making pydoctor a bit happier.
22
in an on-demand fashion. Typically use looks like::
23
1996.1.26 by John Arbash Meinel
Update HACKING and docstrings
24
    from bzrlib.lazy_import import lazy_import
25
    lazy_import(globals(), '''
26
    from bzrlib import (
27
        errors,
28
        osutils,
29
        branch,
30
        )
31
    import bzrlib.branch
32
    ''')
33
5891.1.2 by Andrew Bennetts
Fix a bunch of docstring formatting nits, making pydoctor a bit happier.
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.
1996.1.26 by John Arbash Meinel
Update HACKING and docstrings
36
5891.1.2 by Andrew Bennetts
Fix a bunch of docstring formatting nits, making pydoctor a bit happier.
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).
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
42
"""
43
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
44
from __future__ import absolute_import
45
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
46
47
class ScopeReplacer(object):
48
    """A lazy object that will replace itself in the appropriate scope.
49
50
    This object sits, ready to create the real object the first time it is
51
    needed.
52
    """
53
2399.1.8 by John Arbash Meinel
Change lazy_import to allow proxying when necessary.
54
    __slots__ = ('_scope', '_factory', '_name', '_real_obj')
2413.4.1 by John Arbash Meinel
Cherrypick just the epydoc builder changes.
55
6111.3.2 by Martin von Gagern
Allow subclasses to override _should_proxy.
56
    # If you to do x = y, setting this to False will disallow access to
57
    # members from the second variable (i.e. x). This should normally
58
    # be enabled for reasons of thread safety and documentation, but
59
    # will be disabled during the selftest command to check for abuse.
6111.3.1 by Martin von Gagern
Make lazy imports (at least more) thread-safe.
60
    _should_proxy = True
2399.1.11 by John Arbash Meinel
Update lazy_import with tests for the new '_should_proxy' variable.
61
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
62
    def __init__(self, scope, factory, name):
63
        """Create a temporary object in the specified scope.
64
        Once used, a real object will be placed in the scope.
65
66
        :param scope: The scope the object should appear in
67
        :param factory: A callable that will create the real object.
68
            It will be passed (self, scope, name)
69
        :param name: The variable name in the given scope.
70
        """
1551.18.22 by Aaron Bentley
Fix exception when ScopeReplacer is assigned to before retrieving any members
71
        object.__setattr__(self, '_scope', scope)
72
        object.__setattr__(self, '_factory', factory)
73
        object.__setattr__(self, '_name', name)
74
        object.__setattr__(self, '_real_obj', None)
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
75
        scope[name] = self
76
6111.3.1 by Martin von Gagern
Make lazy imports (at least more) thread-safe.
77
    def _resolve(self):
78
        """Return the real object for which this is a placeholder"""
6111.3.8 by Martin Packman
Fold ScopeReplacer._duplicate_replacement back into object replacing method
79
        name = object.__getattribute__(self, '_name')
6111.3.1 by Martin von Gagern
Make lazy imports (at least more) thread-safe.
80
        real_obj = object.__getattribute__(self, '_real_obj')
6111.3.8 by Martin Packman
Fold ScopeReplacer._duplicate_replacement back into object replacing method
81
        if real_obj is None:
82
            # No obj generated previously, so generate from factory and scope.
83
            factory = object.__getattribute__(self, '_factory')
84
            scope = object.__getattribute__(self, '_scope')
85
            obj = factory(self, scope, name)
86
            if obj is self:
87
                raise errors.IllegalUseOfScopeReplacer(name, msg="Object tried"
88
                    " to replace itself, check it's not using its own scope.")
89
90
            # Check if another thread has jumped in while obj was generated.
91
            real_obj = object.__getattribute__(self, '_real_obj')
92
            if real_obj is None:
93
                # Still no prexisting obj, so go ahead and assign to scope and
94
                # return. There is still a small window here where races will
95
                # not be detected, but safest to avoid additional locking.
96
                object.__setattr__(self, '_real_obj', obj)
97
                scope[name] = obj
98
                return obj
99
100
        # Raise if proxying is disabled as obj has already been generated.
101
        if not ScopeReplacer._should_proxy:
102
            raise errors.IllegalUseOfScopeReplacer(
103
                name, msg="Object already replaced, did you assign it"
104
                          " to another variable?")
105
        return real_obj
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
106
107
    def __getattribute__(self, attr):
6111.3.1 by Martin von Gagern
Make lazy imports (at least more) thread-safe.
108
        obj = object.__getattribute__(self, '_resolve')()
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
109
        return getattr(obj, attr)
110
1551.18.22 by Aaron Bentley
Fix exception when ScopeReplacer is assigned to before retrieving any members
111
    def __setattr__(self, attr, value):
6111.3.1 by Martin von Gagern
Make lazy imports (at least more) thread-safe.
112
        obj = object.__getattribute__(self, '_resolve')()
1551.18.22 by Aaron Bentley
Fix exception when ScopeReplacer is assigned to before retrieving any members
113
        return setattr(obj, attr, value)
114
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
115
    def __call__(self, *args, **kwargs):
6111.3.1 by Martin von Gagern
Make lazy imports (at least more) thread-safe.
116
        obj = object.__getattribute__(self, '_resolve')()
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
117
        return obj(*args, **kwargs)
118
6111.3.1 by Martin von Gagern
Make lazy imports (at least more) thread-safe.
119
120
def disallow_proxying():
121
    """Disallow lazily imported modules to be used as proxies.
122
123
    Calling this function might cause problems with concurrent imports
124
    in multithreaded environments, but will help detecting wasteful
125
    indirection, so it should be called when executing unit tests.
126
6111.3.5 by Martin Packman
Remove _last_duplicate_replacement complication from lazy imports
127
    Only lazy imports that happen after this call are affected.
128
    """
6111.3.1 by Martin von Gagern
Make lazy imports (at least more) thread-safe.
129
    ScopeReplacer._should_proxy = False
130
1996.1.1 by John Arbash Meinel
Adding a ScopeReplacer class, which can replace itself on demand
131
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
132
class ImportReplacer(ScopeReplacer):
133
    """This is designed to replace only a portion of an import list.
134
135
    It will replace itself with a module, and then make children
136
    entries also ImportReplacer objects.
137
138
    At present, this only supports 'import foo.bar.baz' syntax.
139
    """
140
1996.1.23 by John Arbash Meinel
Clean up comment as suggested by Robert
141
    # '_import_replacer_children' is intentionally a long semi-unique name
142
    # that won't likely exist elsewhere. This allows us to detect an
143
    # ImportReplacer object by using
144
    #       object.__getattribute__(obj, '_import_replacer_children')
145
    # We can't just use 'isinstance(obj, ImportReplacer)', because that
146
    # accesses .__class__, which goes through __getattribute__, and triggers
147
    # the replacement.
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
148
    __slots__ = ('_import_replacer_children', '_member', '_module_path')
149
1996.1.15 by John Arbash Meinel
Everything is now hooked up
150
    def __init__(self, scope, name, module_path, member=None, children={}):
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
151
        """Upon request import 'module_path' as the name 'module_name'.
152
        When imported, prepare children to also be imported.
153
154
        :param scope: The scope that objects should be imported into.
155
            Typically this is globals()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
156
        :param name: The variable name. Often this is the same as the
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
157
            module_path. 'bzrlib'
1996.1.4 by John Arbash Meinel
Change how parameters are passed to support 'import root1.mod1 as mod1'
158
        :param module_path: A list for the fully specified module path
159
            ['bzrlib', 'foo', 'bar']
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
160
        :param member: The member inside the module to import, often this is
161
            None, indicating the module is being imported.
162
        :param children: Children entries to be imported later.
1996.1.15 by John Arbash Meinel
Everything is now hooked up
163
            This should be a map of children specifications.
5891.1.2 by Andrew Bennetts
Fix a bunch of docstring formatting nits, making pydoctor a bit happier.
164
            ::
165
            
166
                {'foo':(['bzrlib', 'foo'], None,
167
                    {'bar':(['bzrlib', 'foo', 'bar'], None {})})
168
                }
169
170
        Examples::
171
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
172
            import foo => name='foo' module_path='foo',
1996.1.15 by John Arbash Meinel
Everything is now hooked up
173
                          member=None, children={}
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
174
            import foo.bar => name='foo' module_path='foo', member=None,
1996.1.15 by John Arbash Meinel
Everything is now hooked up
175
                              children={'bar':(['foo', 'bar'], None, {}}
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
176
            from foo import bar => name='bar' module_path='foo', member='bar'
1996.1.15 by John Arbash Meinel
Everything is now hooked up
177
                                   children={}
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
178
            from foo import bar, baz would get translated into 2 import
179
            requests. On for 'name=bar' and one for 'name=baz'
180
        """
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
181
        if (member is not None) and children:
182
            raise ValueError('Cannot supply both a member and children')
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
183
1551.18.22 by Aaron Bentley
Fix exception when ScopeReplacer is assigned to before retrieving any members
184
        object.__setattr__(self, '_import_replacer_children', children)
185
        object.__setattr__(self, '_member', member)
186
        object.__setattr__(self, '_module_path', module_path)
1996.1.3 by John Arbash Meinel
Basic single-level imports work
187
188
        # Indirecting through __class__ so that children can
189
        # override _import (especially our instrumented version)
190
        cls = object.__getattribute__(self, '__class__')
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
191
        ScopeReplacer.__init__(self, scope=scope, name=name,
1996.1.3 by John Arbash Meinel
Basic single-level imports work
192
                               factory=cls._import)
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
193
194
    def _import(self, scope, name):
195
        children = object.__getattribute__(self, '_import_replacer_children')
196
        member = object.__getattribute__(self, '_member')
197
        module_path = object.__getattribute__(self, '_module_path')
1996.1.4 by John Arbash Meinel
Change how parameters are passed to support 'import root1.mod1 as mod1'
198
        module_python_path = '.'.join(module_path)
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
199
        if member is not None:
6355.2.1 by Jelmer Vernooij
Lazy imports can only be absolute.
200
            module = __import__(module_python_path, scope, scope, [member], level=0)
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
201
            return getattr(module, member)
202
        else:
6355.2.1 by Jelmer Vernooij
Lazy imports can only be absolute.
203
            module = __import__(module_python_path, scope, scope, [], level=0)
1996.1.4 by John Arbash Meinel
Change how parameters are passed to support 'import root1.mod1 as mod1'
204
            for path in module_path[1:]:
205
                module = getattr(module, path)
1996.1.2 by John Arbash Meinel
start working on some lazy importing code
206
207
        # Prepare the children to be imported
1996.1.15 by John Arbash Meinel
Everything is now hooked up
208
        for child_name, (child_path, child_member, grandchildren) in \
209
                children.iteritems():
1996.1.5 by John Arbash Meinel
Test that we can lazy import a module, and its children
210
            # Using self.__class__, so that children get children classes
211
            # instantiated. (This helps with instrumented tests)
212
            cls = object.__getattribute__(self, '__class__')
213
            cls(module.__dict__, name=child_name,
1996.1.15 by John Arbash Meinel
Everything is now hooked up
214
                module_path=child_path, member=child_member,
1996.1.5 by John Arbash Meinel
Test that we can lazy import a module, and its children
215
                children=grandchildren)
1996.1.3 by John Arbash Meinel
Basic single-level imports work
216
        return module
1996.1.9 by John Arbash Meinel
Create a method for handling 'import *' syntax.
217
218
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
219
class ImportProcessor(object):
1996.1.15 by John Arbash Meinel
Everything is now hooked up
220
    """Convert text that users input into lazy import requests"""
221
1996.1.18 by John Arbash Meinel
Add more structured error handling
222
    # TODO: jam 20060912 This class is probably not strict enough about
223
    #       what type of text it allows. For example, you can do:
224
    #       import (foo, bar), which is not allowed by python.
225
    #       For now, it should be supporting a superset of python import
226
    #       syntax which is all we really care about.
227
1996.1.15 by John Arbash Meinel
Everything is now hooked up
228
    __slots__ = ['imports', '_lazy_import_class']
229
230
    def __init__(self, lazy_import_class=None):
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
231
        self.imports = {}
1996.1.15 by John Arbash Meinel
Everything is now hooked up
232
        if lazy_import_class is None:
233
            self._lazy_import_class = ImportReplacer
234
        else:
235
            self._lazy_import_class = lazy_import_class
236
1996.1.19 by John Arbash Meinel
Write a simple wrapper function to make lazy imports easy.
237
    def lazy_import(self, scope, text):
1996.1.15 by John Arbash Meinel
Everything is now hooked up
238
        """Convert the given text into a bunch of lazy import objects.
239
240
        This takes a text string, which should be similar to normal python
241
        import markup.
242
        """
243
        self._build_map(text)
244
        self._convert_imports(scope)
245
246
    def _convert_imports(self, scope):
247
        # Now convert the map into a set of imports
248
        for name, info in self.imports.iteritems():
249
            self._lazy_import_class(scope, name=name, module_path=info[0],
250
                                    member=info[1], children=info[2])
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
251
1996.1.14 by John Arbash Meinel
Add tests for converting from a string to the final map
252
    def _build_map(self, text):
253
        """Take a string describing imports, and build up the internal map"""
254
        for line in self._canonicalize_import_text(text):
1996.1.18 by John Arbash Meinel
Add more structured error handling
255
            if line.startswith('import '):
1996.1.14 by John Arbash Meinel
Add tests for converting from a string to the final map
256
                self._convert_import_str(line)
1996.1.18 by John Arbash Meinel
Add more structured error handling
257
            elif line.startswith('from '):
1996.1.14 by John Arbash Meinel
Add tests for converting from a string to the final map
258
                self._convert_from_str(line)
1996.1.18 by John Arbash Meinel
Add more structured error handling
259
            else:
260
                raise errors.InvalidImportLine(line,
261
                    "doesn't start with 'import ' or 'from '")
1996.1.14 by John Arbash Meinel
Add tests for converting from a string to the final map
262
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
263
    def _convert_import_str(self, import_str):
264
        """This converts a import string into an import map.
265
266
        This only understands 'import foo, foo.bar, foo.bar.baz as bing'
267
268
        :param import_str: The import string to process
269
        """
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
270
        if not import_str.startswith('import '):
3376.2.8 by Martin Pool
Some review cleanups for assertion removal
271
            raise ValueError('bad import string %r' % (import_str,))
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
272
        import_str = import_str[len('import '):]
273
274
        for path in import_str.split(','):
275
            path = path.strip()
1996.1.14 by John Arbash Meinel
Add tests for converting from a string to the final map
276
            if not path:
277
                continue
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
278
            as_hunks = path.split(' as ')
279
            if len(as_hunks) == 2:
280
                # We have 'as' so this is a different style of import
281
                # 'import foo.bar.baz as bing' creates a local variable
282
                # named 'bing' which points to 'foo.bar.baz'
283
                name = as_hunks[1].strip()
284
                module_path = as_hunks[0].strip().split('.')
1996.1.18 by John Arbash Meinel
Add more structured error handling
285
                if name in self.imports:
286
                    raise errors.ImportNameCollision(name)
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
287
                # No children available in 'import foo as bar'
288
                self.imports[name] = (module_path, None, {})
289
            else:
290
                # Now we need to handle
291
                module_path = path.split('.')
292
                name = module_path[0]
293
                if name not in self.imports:
294
                    # This is a new import that we haven't seen before
295
                    module_def = ([name], None, {})
296
                    self.imports[name] = module_def
297
                else:
298
                    module_def = self.imports[name]
299
300
                cur_path = [name]
301
                cur = module_def[2]
302
                for child in module_path[1:]:
303
                    cur_path.append(child)
304
                    if child in cur:
1996.1.15 by John Arbash Meinel
Everything is now hooked up
305
                        cur = cur[child][2]
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
306
                    else:
307
                        next = (cur_path[:], None, {})
308
                        cur[child] = next
309
                        cur = next[2]
310
311
    def _convert_from_str(self, from_str):
312
        """This converts a 'from foo import bar' string into an import map.
313
314
        :param from_str: The import string to process
315
        """
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
316
        if not from_str.startswith('from '):
317
            raise ValueError('bad from/import %r' % from_str)
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
318
        from_str = from_str[len('from '):]
319
320
        from_module, import_list = from_str.split(' import ')
321
322
        from_module_path = from_module.split('.')
323
324
        for path in import_list.split(','):
325
            path = path.strip()
1996.1.14 by John Arbash Meinel
Add tests for converting from a string to the final map
326
            if not path:
327
                continue
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
328
            as_hunks = path.split(' as ')
329
            if len(as_hunks) == 2:
330
                # We have 'as' so this is a different style of import
331
                # 'import foo.bar.baz as bing' creates a local variable
332
                # named 'bing' which points to 'foo.bar.baz'
333
                name = as_hunks[1].strip()
334
                module = as_hunks[0].strip()
335
            else:
336
                name = module = path
1996.1.18 by John Arbash Meinel
Add more structured error handling
337
            if name in self.imports:
338
                raise errors.ImportNameCollision(name)
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
339
            self.imports[name] = (from_module_path, module, {})
340
1996.1.14 by John Arbash Meinel
Add tests for converting from a string to the final map
341
    def _canonicalize_import_text(self, text):
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
342
        """Take a list of imports, and split it into regularized form.
343
344
        This is meant to take regular import text, and convert it to
345
        the forms that the rest of the converters prefer.
346
        """
347
        out = []
348
        cur = None
349
        continuing = False
350
351
        for line in text.split('\n'):
352
            line = line.strip()
353
            loc = line.find('#')
354
            if loc != -1:
355
                line = line[:loc].strip()
356
357
            if not line:
358
                continue
359
            if cur is not None:
360
                if line.endswith(')'):
361
                    out.append(cur + ' ' + line[:-1])
362
                    cur = None
363
                else:
364
                    cur += ' ' + line
365
            else:
366
                if '(' in line and ')' not in line:
367
                    cur = line.replace('(', '')
368
                else:
369
                    out.append(line.replace('(', '').replace(')', ''))
1996.1.18 by John Arbash Meinel
Add more structured error handling
370
        if cur is not None:
371
            raise errors.InvalidImportLine(cur, 'Unmatched parenthesis')
1996.1.12 by John Arbash Meinel
Switch from individual functions to a class
372
        return out
1996.1.19 by John Arbash Meinel
Write a simple wrapper function to make lazy imports easy.
373
374
375
def lazy_import(scope, text, lazy_import_class=None):
376
    """Create lazy imports for all of the imports in text.
377
5891.1.2 by Andrew Bennetts
Fix a bunch of docstring formatting nits, making pydoctor a bit happier.
378
    This is typically used as something like::
379
380
        from bzrlib.lazy_import import lazy_import
381
        lazy_import(globals(), '''
382
        from bzrlib import (
383
            foo,
384
            bar,
385
            baz,
386
            )
387
        import bzrlib.branch
388
        import bzrlib.transport
389
        ''')
1996.1.19 by John Arbash Meinel
Write a simple wrapper function to make lazy imports easy.
390
391
    Then 'foo, bar, baz' and 'bzrlib' will exist as lazy-loaded
392
    objects which will be replaced with a real object on first use.
393
394
    In general, it is best to only load modules in this way. This is
395
    because other objects (functions/classes/variables) are frequently
396
    used without accessing a member, which means we cannot tell they
397
    have been used.
398
    """
399
    # This is just a helper around ImportProcessor.lazy_import
400
    proc = ImportProcessor(lazy_import_class=lazy_import_class)
401
    return proc.lazy_import(scope, text)
1996.3.19 by John Arbash Meinel
make lazy_import lazily import errors
402
403
404
# The only module that this module depends on is 'bzrlib.errors'. But it
405
# can actually be imported lazily, since we only need it if there is a
406
# problem.
407
408
lazy_import(globals(), """
409
from bzrlib import errors
410
""")