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)
483
467
self.addCleanup(sys.path.remove, base_path)
485
469
original_import = __import__
486
def instrumented_import(mod, scope1, scope2, fromlist):
487
self.actions.append(('import', mod, fromlist))
488
return original_import(mod, scope1, scope2, fromlist)
470
def instrumented_import(mod, scope1, scope2, fromlist, level):
471
self.actions.append(('import', mod, fromlist, level))
472
return original_import(mod, scope1, scope2, fromlist, level)
490
474
__builtins__['__import__'] = original_import
491
475
self.addCleanup(cleanup)
561
545
"""Test that a real import of these modules works"""
562
546
sub_mod_path = '.'.join([self.root_name, self.sub_name,
563
547
self.submoda_name])
564
root = __import__(sub_mod_path, globals(), locals(), [])
548
root = __import__(sub_mod_path, globals(), locals(), [], 0)
565
549
self.assertEqual(1, root.var1)
566
550
self.assertEqual(3, getattr(root, self.sub_name).var3)
567
551
self.assertEqual(4, getattr(getattr(root, self.sub_name),
568
552
self.submoda_name).var4)
570
554
mod_path = '.'.join([self.root_name, self.mod_name])
571
root = __import__(mod_path, globals(), locals(), [])
555
root = __import__(mod_path, globals(), locals(), [], 0)
572
556
self.assertEqual(2, getattr(root, self.mod_name).var2)
574
self.assertEqual([('import', sub_mod_path, []),
575
('import', mod_path, []),
558
self.assertEqual([('import', sub_mod_path, [], 0),
559
('import', mod_path, [], 0),
599
583
self.assertEqual('x', root1.func1('x'))
601
585
self.assertEqual([('__getattribute__', 'var1'),
603
586
('_import', 'root1'),
604
('import', self.root_name, []),
587
('import', self.root_name, [], 0),
607
590
def test_import_mod(self):
625
608
self.assertEqual('y', mod1.func2('y'))
627
610
self.assertEqual([('__getattribute__', 'var2'),
629
611
('_import', 'mod1'),
630
('import', mod_path, []),
612
('import', mod_path, [], 0),
633
615
def test_import_mod_from_root(self):
650
632
self.assertEqual('y', mod2.func2('y'))
652
634
self.assertEqual([('__getattribute__', 'var2'),
654
635
('_import', 'mod2'),
655
('import', self.root_name, [self.mod_name]),
636
('import', self.root_name, [self.mod_name], 0),
658
639
def test_import_root_and_mod(self):
684
665
mod_path = self.root_name + '.' + self.mod_name
685
666
self.assertEqual([('__getattribute__', 'var1'),
687
667
('_import', 'root3'),
688
('import', self.root_name, []),
668
('import', self.root_name, [], 0),
689
669
('__getattribute__', 'var2'),
691
670
('_import', 'mod3'),
692
('import', mod_path, []),
671
('import', mod_path, [], 0),
695
674
def test_import_root_and_root_mod(self):
728
707
mod_path = self.root_name + '.' + self.mod_name
729
708
self.assertEqual([('__getattribute__', 'mod4'),
731
709
('_import', 'root4'),
732
('import', self.root_name, []),
710
('import', self.root_name, [], 0),
733
711
('__getattribute__', 'var2'),
735
712
('_import', 'mod4'),
736
('import', mod_path, []),
713
('import', mod_path, [], 0),
739
716
def test_import_root_sub_submod(self):
792
769
submodb_path = sub_path + '.' + self.submodb_name
794
771
self.assertEqual([('__getattribute__', 'mod5'),
796
772
('_import', 'root5'),
797
('import', self.root_name, []),
773
('import', self.root_name, [], 0),
798
774
('__getattribute__', 'submoda5'),
800
775
('_import', 'sub5'),
801
('import', sub_path, []),
776
('import', sub_path, [], 0),
802
777
('__getattribute__', 'var2'),
804
778
('_import', 'mod5'),
805
('import', mod_path, []),
779
('import', mod_path, [], 0),
806
780
('__getattribute__', 'var4'),
808
781
('_import', 'submoda5'),
809
('import', submoda_path, []),
782
('import', submoda_path, [], 0),
810
783
('__getattribute__', 'var5'),
812
784
('_import', 'submodb5'),
813
('import', submodb_path, []),
785
('import', submodb_path, [], 0),
1104
1076
self.assertEqual('x', root6.func1('x'))
1106
1078
self.assertEqual([('__getattribute__', 'var1'),
1108
1079
('_import', 'root6'),
1109
('import', self.root_name, []),
1080
('import', self.root_name, [], 0),
1110
1081
], self.actions)
1112
1083
def test_import_deep(self):
1140
1111
submoda_path = sub_path + '.' + self.submoda_name
1142
1113
self.assertEqual([('__getattribute__', 'var4'),
1144
1114
('_import', 'submoda7'),
1145
('import', submoda_path, []),
1115
('import', submoda_path, [], 0),
1146
1116
], self.actions)
1148
1118
def test_lazy_import(self):
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):