1167
1169
('_import', 'root8'),
1168
1170
('import', self.root_name, []),
1169
1171
], self.actions)
1173
class TestScopeReplacerReentrance(TestCase):
1174
"""The ScopeReplacer should be reentrant.
1176
Invoking a replacer while an invocation was already on-going leads to a
1177
race to see which invocation will be the first to delete the _factory and
1178
_scope attributes. The loosing caller used to see AttributeErrors (bug
1181
These tests set up a tracer that stops at the moment just before one of
1182
the attributes is being deleted and starts another call to the
1183
functionality in question (__call__, __getattribute__, __setattr_) in
1184
order win the race, setting up the originall caller to loose.
1187
def tracer(self, frame, event, arg):
1188
# Grab the name of the file that contains the code being executed.
1189
filename = frame.f_globals["__file__"]
1190
# Convert ".pyc" and ".pyo" file names to their ".py" equivalent.
1191
filename = re.sub(r'\.py[co]$', '.py', filename)
1192
# If we're executing a line of code from the right module...
1193
if event == 'line' and 'lazy_import.py' in filename:
1194
line = linecache.getline(filename, frame.f_lineno)
1195
# ...and the line of code is the one we're looking for...
1196
if 'del self._factory' in line:
1197
# We don't need to trace any more.
1199
# Run another racer. This one will "win" the race, deleting
1200
# the attributes. When the first racer resumes it will loose
1201
# the race, generating an AttributeError.
1205
def run_race(self, racer):
1207
sys.settrace(self.tracer)
1208
self.racer() # Should not raise an AttributeError
1209
# Make sure the tracer actually found the code it was looking for. If
1210
# not, maybe the code was refactored in such a way that these tests
1211
# aren't needed any more.
1212
self.assertEqual(None, sys.gettrace())
1214
def test_call(self):
1217
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1218
self.run_race(replacer)
1220
def test_setattr(self):
1227
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1232
self.run_race(racer)
1234
def test_getattribute(self):
1241
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1246
self.run_race(racer)