1167
1169
('_import', 'root8'),
1168
1170
('import', self.root_name, []),
1169
1171
], self.actions)
1174
class TestScopeReplacerReentrance(TestCase):
1175
"""The ScopeReplacer should be reentrant.
1177
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
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.
1188
def tracer(self, frame, event, arg):
1189
# Grab the name of the file that contains the code being executed.
1190
filename = frame.f_globals["__file__"]
1191
# Convert ".pyc" and ".pyo" file names to their ".py" equivalent.
1192
filename = re.sub(r'\.py[co]$', '.py', filename)
1193
# 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.
1206
def run_race(self, racer):
1208
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.
1213
self.assertEqual(None, sys.gettrace())
1215
def test_call(self):
1218
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1219
self.run_race(replacer)
1221
def test_setattr(self):
1228
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1233
self.run_race(racer)
1235
def test_getattribute(self):
1242
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1247
self.run_race(racer)