/brz/remove-bazaar

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