62
58
InstrumentedImportReplacer.actions.append(('_import', name))
63
59
return lazy_import.ImportReplacer._import(self, scope, name)
66
InstrumentedImportReplacer.actions.append('_replace')
67
return lazy_import.ScopeReplacer._replace(self)
69
61
def __getattribute__(self, attr):
70
62
InstrumentedImportReplacer.actions.append(('__getattribute__', attr))
71
63
return lazy_import.ScopeReplacer.__getattribute__(self, attr)
684
665
mod_path = self.root_name + '.' + self.mod_name
685
666
self.assertEqual([('__getattribute__', 'var1'),
687
667
('_import', 'root3'),
688
668
('import', self.root_name, [], 0),
689
669
('__getattribute__', 'var2'),
691
670
('_import', 'mod3'),
692
671
('import', mod_path, [], 0),
728
707
mod_path = self.root_name + '.' + self.mod_name
729
708
self.assertEqual([('__getattribute__', 'mod4'),
731
709
('_import', 'root4'),
732
710
('import', self.root_name, [], 0),
733
711
('__getattribute__', 'var2'),
735
712
('_import', 'mod4'),
736
713
('import', mod_path, [], 0),
792
769
submodb_path = sub_path + '.' + self.submodb_name
794
771
self.assertEqual([('__getattribute__', 'mod5'),
796
772
('_import', 'root5'),
797
773
('import', self.root_name, [], 0),
798
774
('__getattribute__', 'submoda5'),
800
775
('_import', 'sub5'),
801
776
('import', sub_path, [], 0),
802
777
('__getattribute__', 'var2'),
804
778
('_import', 'mod5'),
805
779
('import', mod_path, [], 0),
806
780
('__getattribute__', 'var4'),
808
781
('_import', 'submoda5'),
809
782
('import', submoda_path, [], 0),
810
783
('__getattribute__', 'var5'),
812
784
('_import', 'submodb5'),
813
785
('import', submodb_path, [], 0),
1175
1144
"""The ScopeReplacer should be reentrant.
1177
1146
Invoking a replacer while an invocation was already on-going leads to a
1178
race to see which invocation will be the first to delete the _factory and
1179
_scope attributes. The loosing caller used to see AttributeErrors (bug
1147
race to see which invocation will be the first to call _replace.
1148
The losing caller used to see an exception (bugs 396819 and 702914).
1182
These tests set up a tracer that stops at the moment just before one of
1183
the attributes is being deleted and starts another call to the
1184
functionality in question (__call__, __getattribute__, __setattr_) in
1185
order win the race, setting up the originall caller to loose.
1150
These tests set up a tracer that stops at a suitable moment (upon
1151
entry of a specified method) and starts another call to the
1152
functionality in question (__call__, __getattribute__, __setattr_)
1153
in order to win the race, setting up the original caller to lose.
1188
1156
def tracer(self, frame, event, arg):
1189
1159
# Grab the name of the file that contains the code being executed.
1190
filename = frame.f_globals["__file__"]
1161
filename = code.co_filename
1191
1162
# Convert ".pyc" and ".pyo" file names to their ".py" equivalent.
1192
1163
filename = re.sub(r'\.py[co]$', '.py', filename)
1164
function_name = code.co_name
1193
1165
# If we're executing a line of code from the right module...
1194
if event == 'line' and 'lazy_import.py' in filename:
1195
line = linecache.getline(filename, frame.f_lineno)
1196
# ...and the line of code is the one we're looking for...
1197
if 'del self._factory' in line:
1198
# We don't need to trace any more.
1200
# Run another racer. This one will "win" the race, deleting
1201
# the attributes. When the first racer resumes it will loose
1202
# the race, generating an AttributeError.
1166
if (filename.endswith('lazy_import.py') and
1167
function_name == self.method_to_trace):
1168
# We don't need to trace any more.
1170
# Run another racer. This one will "win" the race.
1204
1172
return self.tracer
1206
def run_race(self, racer):
1174
def run_race(self, racer, method_to_trace='_resolve'):
1175
self.overrideAttr(lazy_import.ScopeReplacer, '_should_proxy', True)
1207
1176
self.racer = racer
1177
self.method_to_trace = method_to_trace
1208
1178
sys.settrace(self.tracer)
1209
self.racer() # Should not raise an AttributeError
1210
# Make sure the tracer actually found the code it was looking for. If
1211
# not, maybe the code was refactored in such a way that these tests
1212
# aren't needed any more.
1179
self.racer() # Should not raise any exception
1180
# Make sure the tracer actually found the code it was
1181
# looking for. If not, maybe the code was refactored in
1182
# such a way that these tests aren't needed any more.
1213
1183
self.assertEqual(None, sys.gettrace())
1215
1185
def test_call(self):