37
39
def use_actions(actions):
38
40
InstrumentedReplacer.actions = actions
41
InstrumentedReplacer.actions.append('_replace')
42
return lazy_import.ScopeReplacer._replace(self)
44
42
def __getattribute__(self, attr):
45
43
InstrumentedReplacer.actions.append(('__getattribute__', attr))
46
44
return lazy_import.ScopeReplacer.__getattribute__(self, attr)
60
58
InstrumentedImportReplacer.actions.append(('_import', name))
61
59
return lazy_import.ImportReplacer._import(self, scope, name)
64
InstrumentedImportReplacer.actions.append('_replace')
65
return lazy_import.ScopeReplacer._replace(self)
67
61
def __getattribute__(self, attr):
68
62
InstrumentedImportReplacer.actions.append(('__getattribute__', attr))
69
63
return lazy_import.ScopeReplacer.__getattribute__(self, attr)
481
467
self.addCleanup(sys.path.remove, base_path)
483
469
original_import = __import__
484
def instrumented_import(mod, scope1, scope2, fromlist):
485
self.actions.append(('import', mod, fromlist))
486
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)
488
474
__builtins__['__import__'] = original_import
489
475
self.addCleanup(cleanup)
559
545
"""Test that a real import of these modules works"""
560
546
sub_mod_path = '.'.join([self.root_name, self.sub_name,
561
547
self.submoda_name])
562
root = __import__(sub_mod_path, globals(), locals(), [])
548
root = __import__(sub_mod_path, globals(), locals(), [], 0)
563
549
self.assertEqual(1, root.var1)
564
550
self.assertEqual(3, getattr(root, self.sub_name).var3)
565
551
self.assertEqual(4, getattr(getattr(root, self.sub_name),
566
552
self.submoda_name).var4)
568
554
mod_path = '.'.join([self.root_name, self.mod_name])
569
root = __import__(mod_path, globals(), locals(), [])
555
root = __import__(mod_path, globals(), locals(), [], 0)
570
556
self.assertEqual(2, getattr(root, self.mod_name).var2)
572
self.assertEqual([('import', sub_mod_path, []),
573
('import', mod_path, []),
558
self.assertEqual([('import', sub_mod_path, [], 0),
559
('import', mod_path, [], 0),
597
583
self.assertEqual('x', root1.func1('x'))
599
585
self.assertEqual([('__getattribute__', 'var1'),
601
586
('_import', 'root1'),
602
('import', self.root_name, []),
587
('import', self.root_name, [], 0),
605
590
def test_import_mod(self):
623
608
self.assertEqual('y', mod1.func2('y'))
625
610
self.assertEqual([('__getattribute__', 'var2'),
627
611
('_import', 'mod1'),
628
('import', mod_path, []),
612
('import', mod_path, [], 0),
631
615
def test_import_mod_from_root(self):
648
632
self.assertEqual('y', mod2.func2('y'))
650
634
self.assertEqual([('__getattribute__', 'var2'),
652
635
('_import', 'mod2'),
653
('import', self.root_name, [self.mod_name]),
636
('import', self.root_name, [self.mod_name], 0),
656
639
def test_import_root_and_mod(self):
682
665
mod_path = self.root_name + '.' + self.mod_name
683
666
self.assertEqual([('__getattribute__', 'var1'),
685
667
('_import', 'root3'),
686
('import', self.root_name, []),
668
('import', self.root_name, [], 0),
687
669
('__getattribute__', 'var2'),
689
670
('_import', 'mod3'),
690
('import', mod_path, []),
671
('import', mod_path, [], 0),
693
674
def test_import_root_and_root_mod(self):
726
707
mod_path = self.root_name + '.' + self.mod_name
727
708
self.assertEqual([('__getattribute__', 'mod4'),
729
709
('_import', 'root4'),
730
('import', self.root_name, []),
710
('import', self.root_name, [], 0),
731
711
('__getattribute__', 'var2'),
733
712
('_import', 'mod4'),
734
('import', mod_path, []),
713
('import', mod_path, [], 0),
737
716
def test_import_root_sub_submod(self):
790
769
submodb_path = sub_path + '.' + self.submodb_name
792
771
self.assertEqual([('__getattribute__', 'mod5'),
794
772
('_import', 'root5'),
795
('import', self.root_name, []),
773
('import', self.root_name, [], 0),
796
774
('__getattribute__', 'submoda5'),
798
775
('_import', 'sub5'),
799
('import', sub_path, []),
776
('import', sub_path, [], 0),
800
777
('__getattribute__', 'var2'),
802
778
('_import', 'mod5'),
803
('import', mod_path, []),
779
('import', mod_path, [], 0),
804
780
('__getattribute__', 'var4'),
806
781
('_import', 'submoda5'),
807
('import', submoda_path, []),
782
('import', submoda_path, [], 0),
808
783
('__getattribute__', 'var5'),
810
784
('_import', 'submodb5'),
811
('import', submodb_path, []),
785
('import', submodb_path, [], 0),
1102
1076
self.assertEqual('x', root6.func1('x'))
1104
1078
self.assertEqual([('__getattribute__', 'var1'),
1106
1079
('_import', 'root6'),
1107
('import', self.root_name, []),
1080
('import', self.root_name, [], 0),
1108
1081
], self.actions)
1110
1083
def test_import_deep(self):
1138
1111
submoda_path = sub_path + '.' + self.submoda_name
1140
1113
self.assertEqual([('__getattribute__', 'var4'),
1142
1114
('_import', 'submoda7'),
1143
('import', submoda_path, []),
1115
('import', submoda_path, [], 0),
1144
1116
], self.actions)
1146
1118
def test_lazy_import(self):
1163
1135
self.assertEqual(1, root8.func1(1))
1165
1137
self.assertEqual([('__getattribute__', 'var1'),
1167
1138
('_import', 'root8'),
1168
('import', self.root_name, []),
1139
('import', self.root_name, [], 0),
1169
1140
], self.actions)
1143
class TestScopeReplacerReentrance(TestCase):
1144
"""The ScopeReplacer should be reentrant.
1146
Invoking a replacer while an invocation was already on-going leads to a
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).
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.
1156
def tracer(self, frame, event, arg):
1159
# Grab the name of the file that contains the code being executed.
1161
filename = code.co_filename
1162
# Convert ".pyc" and ".pyo" file names to their ".py" equivalent.
1163
filename = re.sub(r'\.py[co]$', '.py', filename)
1164
function_name = code.co_name
1165
# If we're executing a line of code from the right module...
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.
1174
def run_race(self, racer, method_to_trace='_resolve'):
1175
self.overrideAttr(lazy_import.ScopeReplacer, '_should_proxy', True)
1177
self.method_to_trace = method_to_trace
1178
sys.settrace(self.tracer)
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.
1183
self.assertEqual(None, sys.gettrace())
1185
def test_call(self):
1188
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1189
self.run_race(replacer)
1191
def test_setattr(self):
1198
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1203
self.run_race(racer)
1205
def test_getattribute(self):
1212
replacer = lazy_import.ScopeReplacer({}, factory, 'name')
1217
self.run_race(racer)