Mercurial > hg-stable
comparison hgdemandimport/demandimportpy2.py @ 39284: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
39283:4019b4542e61 | 39284: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] |