comparison hgdemandimport/demandimportpy2.py @ 39256:574e1d3bc667

demandimport: instrument python 2 code with trace events This causes the evaluation of an import in Python 3 to emit some trace data. There's some interesting wrinkles in here, like the fact that before we even hit dispatch we've demand-imported `sys` several times, despite the fact that `sys` was already fully loaded as one of the first few statements in the `hg` script. I don't think that's actually costing us a ton of performance, but it's probably something we should investigate fixing some day. Differential Revision: https://phab.mercurial-scm.org/D4347
author Augie Fackler <augie@google.com>
date Tue, 21 Aug 2018 15:27:30 -0400
parents 670eb4fa1b86
children 2372284d9457
comparison
equal deleted inserted replaced
39255:4019b4542e61 39256:574e1d3bc667
27 from __future__ import absolute_import 27 from __future__ import absolute_import
28 28
29 import __builtin__ as builtins 29 import __builtin__ as builtins
30 import contextlib 30 import contextlib
31 import sys 31 import sys
32
33 from . import tracing
32 34
33 contextmanager = contextlib.contextmanager 35 contextmanager = contextlib.contextmanager
34 36
35 _origimport = __import__ 37 _origimport = __import__
36 38
84 """ 86 """
85 self._data[5].add(name) 87 self._data[5].add(name)
86 88
87 def _load(self): 89 def _load(self):
88 if not self._module: 90 if not self._module:
89 head, globals, locals, after, level, modrefs = self._data 91 with tracing.log('demandimport %s', self._data[0]):
90 mod = _hgextimport(_origimport, head, globals, locals, None, level) 92 head, globals, locals, after, level, modrefs = self._data
91 if mod is self: 93 mod = _hgextimport(
92 # In this case, _hgextimport() above should imply 94 _origimport, head, globals, locals, None, level)
93 # _demandimport(). Otherwise, _hgextimport() never 95 if mod is self:
94 # returns _demandmod. This isn't intentional behavior, 96 # In this case, _hgextimport() above should imply
95 # in fact. (see also issue5304 for detail) 97 # _demandimport(). Otherwise, _hgextimport() never
96 # 98 # returns _demandmod. This isn't intentional behavior,
97 # If self._module is already bound at this point, self 99 # in fact. (see also issue5304 for detail)
98 # should be already _load()-ed while _hgextimport(). 100 #
99 # Otherwise, there is no way to import actual module 101 # If self._module is already bound at this point, self
100 # as expected, because (re-)invoking _hgextimport() 102 # should be already _load()-ed while _hgextimport().
101 # should cause same result. 103 # Otherwise, there is no way to import actual module
102 # This is reason why _load() returns without any more 104 # as expected, because (re-)invoking _hgextimport()
103 # setup but assumes self to be already bound. 105 # should cause same result.
104 mod = self._module 106 # This is reason why _load() returns without any more
105 assert mod and mod is not self, "%s, %s" % (self, mod) 107 # setup but assumes self to be already bound.
106 return 108 mod = self._module
107 109 assert mod and mod is not self, "%s, %s" % (self, mod)
108 # load submodules 110 return
109 def subload(mod, p): 111
110 h, t = p, None 112 # load submodules
111 if '.' in p: 113 def subload(mod, p):
112 h, t = p.split('.', 1) 114 h, t = p, None
113 if getattr(mod, h, nothing) is nothing: 115 if '.' in p:
114 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__, 116 h, t = p.split('.', 1)
115 level=1)) 117 if getattr(mod, h, nothing) is nothing:
116 elif t: 118 setattr(mod, h, _demandmod(
117 subload(getattr(mod, h), t) 119 p, mod.__dict__, mod.__dict__, level=1))
118 120 elif t:
119 for x in after: 121 subload(getattr(mod, h), t)
120 subload(mod, x) 122
121 123 for x in after:
122 # Replace references to this proxy instance with the actual module. 124 subload(mod, x)
123 if locals: 125
124 if locals.get(head) is self: 126 # Replace references to this proxy instance with the
125 locals[head] = mod 127 # actual module.
126 elif locals.get(head + r'mod') is self: 128 if locals:
127 locals[head + r'mod'] = mod 129 if locals.get(head) is self:
128 130 locals[head] = mod
129 for modname in modrefs: 131 elif locals.get(head + r'mod') is self:
130 modref = sys.modules.get(modname, None) 132 locals[head + r'mod'] = mod
131 if modref and getattr(modref, head, None) is self: 133
132 setattr(modref, head, mod) 134 for modname in modrefs:
133 135 modref = sys.modules.get(modname, None)
134 object.__setattr__(self, r"_module", mod) 136 if modref and getattr(modref, head, None) is self:
137 setattr(modref, head, mod)
138
139 object.__setattr__(self, r"_module", mod)
135 140
136 def __repr__(self): 141 def __repr__(self):
137 if self._module: 142 if self._module:
138 return "<proxied module '%s'>" % self._data[0] 143 return "<proxied module '%s'>" % self._data[0]
139 return "<unloaded module '%s'>" % self._data[0] 144 return "<unloaded module '%s'>" % self._data[0]