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