mercurial/demandload.py
author Vadim Gelfer <vadim.gelfer@gmail.com>
Tue, 01 Aug 2006 15:40:28 -0700
changeset 2757 787e18b84893
parent 2310 d01eac5968c6
child 2807 a8a7ce1a01a5
permissions -rw-r--r--
merge patches from brendan cully that did not apply clean against tip.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1826
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     1
'''Demand load modules when used, not when imported.'''
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     2
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     3
__author__ = '''Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>.
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     4
This software may be used and distributed according to the terms
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     5
of the GNU General Public License, incorporated herein by reference.'''
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     6
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     7
# this is based on matt's original demandload module.  it is a
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     8
# complete rewrite.  some time, we may need to support syntax of
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
     9
# "import foo as bar".
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    10
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    11
class _importer(object):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    12
    '''import a module.  it is not imported until needed, and is
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    13
    imported at most once per scope.'''
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    14
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    15
    def __init__(self, scope, modname, fromlist):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    16
        '''scope is context (globals() or locals()) in which import
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    17
        should be made.  modname is name of module to import.
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    18
        fromlist is list of modules for "from foo import ..."
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    19
        emulation.'''
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    20
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    21
        self.scope = scope
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    22
        self.modname = modname
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    23
        self.fromlist = fromlist
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    24
        self.mod = None
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    25
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    26
    def module(self):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    27
        '''import the module if needed, and return.'''
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    28
        if self.mod is None:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    29
            self.mod = __import__(self.modname, self.scope, self.scope,
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    30
                                  self.fromlist)
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    31
            del self.modname, self.fromlist
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    32
        return self.mod
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    33
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    34
class _replacer(object):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    35
    '''placeholder for a demand loaded module. demandload puts this in
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    36
    a target scope.  when an attribute of this object is looked up,
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    37
    this object is replaced in the target scope with the actual
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    38
    module.
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    39
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    40
    we use __getattribute__ to avoid namespace clashes between
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    41
    placeholder object and real module.'''
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    42
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    43
    def __init__(self, importer, target):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    44
        self.importer = importer
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    45
        self.target = target
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    46
        # consider case where we do this:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    47
        #   demandload(globals(), 'foo.bar foo.quux')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    48
        # foo will already exist in target scope when we get to
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    49
        # foo.quux.  so we remember that we will need to demandload
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    50
        # quux into foo's scope when we really load it.
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    51
        self.later = []
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    52
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    53
    def module(self):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    54
        return object.__getattribute__(self, 'importer').module()
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    55
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    56
    def __getattribute__(self, key):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    57
        '''look up an attribute in a module and return it. replace the
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    58
        name of the module in the caller\'s dict with the actual
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    59
        module.'''
262
3db700146536 implement demand loading hack
mpm@selenic.com
parents:
diff changeset
    60
1826
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    61
        module = object.__getattribute__(self, 'module')()
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    62
        target = object.__getattribute__(self, 'target')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    63
        importer = object.__getattribute__(self, 'importer')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    64
        later = object.__getattribute__(self, 'later')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    65
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    66
        if later:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    67
            demandload(module.__dict__, ' '.join(later))
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    68
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    69
        importer.scope[target] = module
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    70
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    71
        return getattr(module, key)
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    72
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    73
class _replacer_from(_replacer):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    74
    '''placeholder for a demand loaded module.  used for "from foo
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    75
    import ..." emulation. semantics of this are different than
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    76
    regular import, so different implementation needed.'''
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    77
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    78
    def module(self):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    79
        importer = object.__getattribute__(self, 'importer')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    80
        target = object.__getattribute__(self, 'target')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    81
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    82
        return getattr(importer.module(), target)
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    83
2310
d01eac5968c6 demandload: implement __call__
John Arbash Meinel <john@arbash-meinel.com>
parents: 1826
diff changeset
    84
    def __call__(self, *args, **kwargs):
d01eac5968c6 demandload: implement __call__
John Arbash Meinel <john@arbash-meinel.com>
parents: 1826
diff changeset
    85
        target = object.__getattribute__(self, 'module')()
d01eac5968c6 demandload: implement __call__
John Arbash Meinel <john@arbash-meinel.com>
parents: 1826
diff changeset
    86
        return target(*args, **kwargs)
d01eac5968c6 demandload: implement __call__
John Arbash Meinel <john@arbash-meinel.com>
parents: 1826
diff changeset
    87
1826
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    88
def demandload(scope, modules):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    89
    '''import modules into scope when each is first used.
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    90
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    91
    scope should be the value of globals() in the module calling this
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    92
    function, or locals() in the calling function.
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    93
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    94
    modules is a string listing module names, separated by white
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    95
    space.  names are handled like this:
262
3db700146536 implement demand loading hack
mpm@selenic.com
parents:
diff changeset
    96
1826
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    97
    foo            import foo
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    98
    foo bar        import foo, bar
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
    99
    foo.bar        import foo.bar
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   100
    foo:bar        from foo import bar
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   101
    foo:bar,quux   from foo import bar, quux
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   102
    foo.bar:quux   from foo.bar import quux'''
262
3db700146536 implement demand loading hack
mpm@selenic.com
parents:
diff changeset
   103
1826
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   104
    for mod in modules.split():
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   105
        col = mod.find(':')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   106
        if col >= 0:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   107
            fromlist = mod[col+1:].split(',')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   108
            mod = mod[:col]
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   109
        else:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   110
            fromlist = []
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   111
        importer = _importer(scope, mod, fromlist)
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   112
        if fromlist:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   113
            for name in fromlist:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   114
                scope[name] = _replacer_from(importer, name)
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   115
        else:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   116
            dot = mod.find('.')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   117
            if dot >= 0:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   118
                basemod = mod[:dot]
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   119
                val = scope.get(basemod)
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   120
                # if base module has already been demandload()ed,
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   121
                # remember to load this submodule into its namespace
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   122
                # when needed.
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   123
                if isinstance(val, _replacer):
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   124
                    later = object.__getattribute__(val, 'later')
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   125
                    later.append(mod[dot+1:])
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   126
                    continue
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   127
            else:
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   128
                basemod = mod
f3abe0bdccdd rewrite demandload module to be more flexible.
Vadim Gelfer <vadim.gelger@gmail.com>
parents: 262
diff changeset
   129
            scope[basemod] = _replacer(importer, basemod)