~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_lazy_import.py

  • Committer: Jelmer Vernooij
  • Date: 2012-01-06 22:44:57 UTC
  • mfrom: (6436 +trunk)
  • mto: (6437.3.11 2.5)
  • mto: This revision was merged to the branch mainline in revision 6444.
  • Revision ID: jelmer@samba.org-20120106224457-re0pcy0fz31xob77
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
    def use_actions(actions):
40
40
        InstrumentedReplacer.actions = actions
41
41
 
42
 
    def _replace(self):
43
 
        InstrumentedReplacer.actions.append('_replace')
44
 
        return lazy_import.ScopeReplacer._replace(self)
45
 
 
46
42
    def __getattribute__(self, attr):
47
43
        InstrumentedReplacer.actions.append(('__getattribute__', attr))
48
44
        return lazy_import.ScopeReplacer.__getattribute__(self, attr)
62
58
        InstrumentedImportReplacer.actions.append(('_import', name))
63
59
        return lazy_import.ImportReplacer._import(self, scope, name)
64
60
 
65
 
    def _replace(self):
66
 
        InstrumentedImportReplacer.actions.append('_replace')
67
 
        return lazy_import.ScopeReplacer._replace(self)
68
 
 
69
61
    def __getattribute__(self, attr):
70
62
        InstrumentedImportReplacer.actions.append(('__getattribute__', attr))
71
63
        return lazy_import.ScopeReplacer.__getattribute__(self, attr)
144
136
        self.assertIsInstance(test_obj1, TestClass)
145
137
        self.assertEqual('foo', test_obj1.foo(2))
146
138
        self.assertEqual([('__getattribute__', 'foo'),
147
 
                          '_replace',
148
139
                          'factory',
149
140
                          'init',
150
141
                          ('foo', 1),
243
234
        self.assertEqual('class_member', test_class1.class_member)
244
235
        self.assertEqual(test_class1, TestClass)
245
236
        self.assertEqual([('__getattribute__', 'class_member'),
246
 
                          '_replace',
247
237
                          'factory',
248
238
                         ], actions)
249
239
 
273
263
        self.assertIsInstance(obj, TestClass)
274
264
        self.assertEqual('class_member', obj.class_member)
275
265
        self.assertEqual([('__call__', (), {}),
276
 
                          '_replace',
277
266
                          'factory',
278
267
                          'init',
279
268
                         ], actions)
306
295
 
307
296
        self.assertEqual((1,2,'3'), val)
308
297
        self.assertEqual([('__call__', (1,2), {'c':'3'}),
309
 
                          '_replace',
310
298
                          'factory',
311
299
                          'func',
312
300
                         ], actions)
368
356
                          getattr, test_obj3, 'foo')
369
357
 
370
358
        self.assertEqual([('__getattribute__', 'foo'),
371
 
                          '_replace',
372
359
                          'factory',
373
360
                          'init',
374
361
                          ('foo', 1),
375
362
                          ('foo', 2),
376
363
                          ('foo', 3),
377
364
                          ('__getattribute__', 'foo'),
378
 
                          '_replace',
379
365
                         ], actions)
380
366
 
381
367
    def test_enable_proxying(self):
426
412
                         object.__getattribute__(test_obj5, '__class__'))
427
413
 
428
414
        self.assertEqual([('__getattribute__', 'foo'),
429
 
                          '_replace',
430
415
                          'factory',
431
416
                          'init',
432
417
                          ('foo', 1),
464
449
        e = self.assertRaises(errors.IllegalUseOfScopeReplacer, test_obj7)
465
450
        self.assertIn("replace itself", e.msg)
466
451
        self.assertEqual([('__call__', (), {}),
467
 
                          '_replace',
468
452
                          'factory'], actions)
469
453
 
470
454
 
483
467
        self.addCleanup(sys.path.remove, base_path)
484
468
 
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)
489
473
        def cleanup():
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)
569
553
 
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)
573
557
 
574
 
        self.assertEqual([('import', sub_mod_path, []),
575
 
                          ('import', mod_path, []),
 
558
        self.assertEqual([('import', sub_mod_path, [], 0),
 
559
                          ('import', mod_path, [], 0),
576
560
                         ], self.actions)
577
561
 
578
562
 
599
583
        self.assertEqual('x', root1.func1('x'))
600
584
 
601
585
        self.assertEqual([('__getattribute__', 'var1'),
602
 
                          '_replace',
603
586
                          ('_import', 'root1'),
604
 
                          ('import', self.root_name, []),
 
587
                          ('import', self.root_name, [], 0),
605
588
                         ], self.actions)
606
589
 
607
590
    def test_import_mod(self):
625
608
        self.assertEqual('y', mod1.func2('y'))
626
609
 
627
610
        self.assertEqual([('__getattribute__', 'var2'),
628
 
                          '_replace',
629
611
                          ('_import', 'mod1'),
630
 
                          ('import', mod_path, []),
 
612
                          ('import', mod_path, [], 0),
631
613
                         ], self.actions)
632
614
 
633
615
    def test_import_mod_from_root(self):
650
632
        self.assertEqual('y', mod2.func2('y'))
651
633
 
652
634
        self.assertEqual([('__getattribute__', 'var2'),
653
 
                          '_replace',
654
635
                          ('_import', 'mod2'),
655
 
                          ('import', self.root_name, [self.mod_name]),
 
636
                          ('import', self.root_name, [self.mod_name], 0),
656
637
                         ], self.actions)
657
638
 
658
639
    def test_import_root_and_mod(self):
683
664
 
684
665
        mod_path = self.root_name + '.' + self.mod_name
685
666
        self.assertEqual([('__getattribute__', 'var1'),
686
 
                          '_replace',
687
667
                          ('_import', 'root3'),
688
 
                          ('import', self.root_name, []),
 
668
                          ('import', self.root_name, [], 0),
689
669
                          ('__getattribute__', 'var2'),
690
 
                          '_replace',
691
670
                          ('_import', 'mod3'),
692
 
                          ('import', mod_path, []),
 
671
                          ('import', mod_path, [], 0),
693
672
                         ], self.actions)
694
673
 
695
674
    def test_import_root_and_root_mod(self):
727
706
 
728
707
        mod_path = self.root_name + '.' + self.mod_name
729
708
        self.assertEqual([('__getattribute__', 'mod4'),
730
 
                          '_replace',
731
709
                          ('_import', 'root4'),
732
 
                          ('import', self.root_name, []),
 
710
                          ('import', self.root_name, [], 0),
733
711
                          ('__getattribute__', 'var2'),
734
 
                          '_replace',
735
712
                          ('_import', 'mod4'),
736
 
                          ('import', mod_path, []),
 
713
                          ('import', mod_path, [], 0),
737
714
                         ], self.actions)
738
715
 
739
716
    def test_import_root_sub_submod(self):
792
769
        submodb_path = sub_path + '.' + self.submodb_name
793
770
 
794
771
        self.assertEqual([('__getattribute__', 'mod5'),
795
 
                          '_replace',
796
772
                          ('_import', 'root5'),
797
 
                          ('import', self.root_name, []),
 
773
                          ('import', self.root_name, [], 0),
798
774
                          ('__getattribute__', 'submoda5'),
799
 
                          '_replace',
800
775
                          ('_import', 'sub5'),
801
 
                          ('import', sub_path, []),
 
776
                          ('import', sub_path, [], 0),
802
777
                          ('__getattribute__', 'var2'),
803
 
                          '_replace',
804
778
                          ('_import', 'mod5'),
805
 
                          ('import', mod_path, []),
 
779
                          ('import', mod_path, [], 0),
806
780
                          ('__getattribute__', 'var4'),
807
 
                          '_replace',
808
781
                          ('_import', 'submoda5'),
809
 
                          ('import', submoda_path, []),
 
782
                          ('import', submoda_path, [], 0),
810
783
                          ('__getattribute__', 'var5'),
811
 
                          '_replace',
812
784
                          ('_import', 'submodb5'),
813
 
                          ('import', submodb_path, []),
 
785
                          ('import', submodb_path, [], 0),
814
786
                         ], self.actions)
815
787
 
816
788
 
1104
1076
        self.assertEqual('x', root6.func1('x'))
1105
1077
 
1106
1078
        self.assertEqual([('__getattribute__', 'var1'),
1107
 
                          '_replace',
1108
1079
                          ('_import', 'root6'),
1109
 
                          ('import', self.root_name, []),
 
1080
                          ('import', self.root_name, [], 0),
1110
1081
                         ], self.actions)
1111
1082
 
1112
1083
    def test_import_deep(self):
1140
1111
        submoda_path = sub_path + '.' + self.submoda_name
1141
1112
 
1142
1113
        self.assertEqual([('__getattribute__', 'var4'),
1143
 
                          '_replace',
1144
1114
                          ('_import', 'submoda7'),
1145
 
                          ('import', submoda_path, []),
 
1115
                          ('import', submoda_path, [], 0),
1146
1116
                         ], self.actions)
1147
1117
 
1148
1118
    def test_lazy_import(self):
1165
1135
        self.assertEqual(1, root8.func1(1))
1166
1136
 
1167
1137
        self.assertEqual([('__getattribute__', 'var1'),
1168
 
                          '_replace',
1169
1138
                          ('_import', 'root8'),
1170
 
                          ('import', self.root_name, []),
 
1139
                          ('import', self.root_name, [], 0),
1171
1140
                         ], self.actions)
1172
1141
 
1173
1142
 
1175
1144
    """The ScopeReplacer should be reentrant.
1176
1145
 
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
1180
 
    702914).
 
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).
1181
1149
 
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.
1186
1154
    """
1187
1155
 
1188
1156
    def tracer(self, frame, event, arg):
 
1157
        if event != 'call':
 
1158
            return self.tracer
1189
1159
        # Grab the name of the file that contains the code being executed.
1190
 
        filename = frame.f_globals["__file__"]
 
1160
        code = frame.f_code
 
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.
1199
 
                sys.settrace(None)
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.
1203
 
                self.racer()
 
1166
        if (filename.endswith('lazy_import.py') and
 
1167
            function_name == self.method_to_trace):
 
1168
            # We don't need to trace any more.
 
1169
            sys.settrace(None)
 
1170
            # Run another racer.  This one will "win" the race.
 
1171
            self.racer()
1204
1172
        return self.tracer
1205
1173
 
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())
1214
1184
 
1215
1185
    def test_call(self):