Completed
Push — master ( e957f2...482997 )
by Max
02:01
created

C.footer()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
cc 1
c 8
b 0
f 0
dl 0
loc 4
rs 10
1
from abc import abstractmethod
2
import abc as abc_main
3
from inspect import isabstract
4
import sys
5
6
import pytest
7
8
9
def test_import_compat(compat):
10
    """Test the module is importable. See conftest.py for the actual import."""
11
    assert compat
12
13
14
def test_import_abc(abc):
15
    """Test the module is importable. See conftest.py for the actual import."""
16
    assert abc
17
18
19
def test_has_class(abc):
20
    assert abc.NamespaceableABC
21
22
23
def test_ABC_helper(abc):
24
    # create an ABC using the helper class and perform basic checks
25
    class C(abc.NamespaceableABC):
26
        @classmethod
27
        @abstractmethod
28
        def footer(cls):
29
            return cls.__name__
30
    assert isinstance(C, abc.NamespaceableABCMeta)
31
    with pytest.raises(TypeError):
32
        print(C())
33
34
    class D(C):
35
        @classmethod
36
        def footer(cls):
37
            return super().footer()
38
    assert D.footer() == 'D'
39
40
41
def test_abstractmethod_basics(abc):
42
    @abstractmethod
43
    def footer(self):
44
        pass
45
    assert footer.__isabstractmethod__
46
47
    def barter(self):
48
        pass
49
    assert not hasattr(barter, "__isabstractmethod__")
50
51
52 View Code Duplication
def test_abstractproperty_basics(abc):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
53
    @property
54
    @abstractmethod
55
    def footer(self):
56
        pass
57
    assert footer.__isabstractmethod__
58
59
    def barter(self):
60
        pass
61
    assert not getattr(barter, "__isabstractmethod__", False)
62
63
    class C(metaclass=abc.NamespaceableABCMeta):
64
        @property
65
        @abstractmethod
66
        def footer(self):
67
            return 3
68
    with pytest.raises(TypeError):
69
        print(C())
70
71
    class D(C):
72
        @C.footer.getter
73
        def footer(self):
74
            return super().footer
75
    assert D().footer == 3
76
77
78
def test_abstractproperty_namespaced(abc, namespace):
79
80
    class C(metaclass=abc.NamespaceableABCMeta):
81
        with namespace() as ns:
82
            @property
83
            @abstractmethod
84
            def footer(self):
85
                return 3
86
    with pytest.raises(TypeError):
87
        print(C())
88
89
    class D(C):
90
        with namespace() as ns:
91
            @C.ns.footer.getter
92
            def footer(self):
93
                return super().ns.footer
94
    assert D().ns.footer == 3
95
96
97 View Code Duplication
def test_abstractclassmethod_basics(abc):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
98
    @classmethod
99
    @abstractmethod
100
    def footer(cls):
101
        pass
102
    assert footer.__isabstractmethod__
103
104
    @classmethod
105
    def barter(cls):
106
        pass
107
    assert not getattr(barter, "__isabstractmethod__", False)
108
109
    class C(metaclass=abc.NamespaceableABCMeta):
110
        @classmethod
111
        @abstractmethod
112
        def footer(cls):
113
            return cls.__name__
114
    with pytest.raises(TypeError):
115
        print(C())
116
117
    class D(C):
118
        @classmethod
119
        def footer(cls):
120
            return super().footer()
121
    assert D.footer() == 'D'
122
    assert D().footer() == 'D'
123
124
125 View Code Duplication
def test_abstractclassmethod_namespaced(abc, namespace):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
126
    class C(metaclass=abc.NamespaceableABCMeta):
127
        with namespace() as ns:
128
            @classmethod
129
            @abstractmethod
130
            def footer(cls):
131
                return cls.__name__
132
    with pytest.raises(TypeError):
133
        print(C())
134
135
    class D(C):
136
        with namespace() as ns:
137
            @classmethod
138
            def footer(cls):
139
                return super().ns.footer()
140
    assert D.ns.footer() == 'D'
141
    assert D().ns.footer() == 'D'
142
143
144
def test_abstractstaticmethod_basics(abc):
145
    @staticmethod
146
    @abstractmethod
147
    def footer():
148
        pass
149
    assert footer.__isabstractmethod__
150
151
    @staticmethod
152
    def barter():
153
        pass
154
    assert not (getattr(barter, "__isabstractmethod__", False))
155
156
    class C(metaclass=abc.NamespaceableABCMeta):
157
        @staticmethod
158
        @abstractmethod
159
        def footer():
160
            return 3
161
    with pytest.raises(TypeError):
162
        print(C())
163
164
    class D(C):
165
        @staticmethod
166
        def footer():
167
            return 4
168
    assert D.footer() == 4
169
    assert D().footer() == 4
170
171
172 View Code Duplication
def test_abstractstaticmethod_namespaced(abc, namespace):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
173
    class C(metaclass=abc.NamespaceableABCMeta):
174
        with namespace() as ns:
175
            @staticmethod
176
            @abstractmethod
177
            def footer():
178
                return 3
179
    with pytest.raises(TypeError):
180
        print(C())
181
182
    class D(C):
183
        with namespace() as ns:
184
            @staticmethod
185
            def footer():
186
                return 4
187
    assert D.ns.footer() == 4
188
    assert D().ns.footer() == 4
189
190
191
def test_abstractmethod_integration(abc):
192
    for abstractthing in [abstractmethod, abc_main.abstractproperty,
193
                          abc_main.abstractclassmethod,
194
                          abc_main.abstractstaticmethod]:
195
        class C(metaclass=abc.NamespaceableABCMeta):
196
            @abstractthing
197
            def footer(self):
198
                pass  # abstract
199
200
            def barter(self):
201
                pass  # concrete
202
        assert C.__abstractmethods__ == {"footer"}
203
        with pytest.raises(TypeError):
204
            print(C())  # because footer is abstract
205
        assert isabstract(C)
206
207
        class D(C):
208
            def barter(self):
209
                pass  # concrete override of concrete
210
        assert D.__abstractmethods__ == {"footer"}
211
        with pytest.raises(TypeError):
212
            print(D())  # because footer is still abstract
213
        assert isabstract(D)
214
215
        class E(D):
216
            def footer(self):
217
                pass
218
        assert E.__abstractmethods__ == set()
219
        E()  # now footer is concrete, too
220
        assert not isabstract(E)
221
222
        class F(E):
223
            @abstractthing
224
            def barter(self):
225
                pass  # abstract override of concrete
226
        assert F.__abstractmethods__ == {"barter"}
227
        with pytest.raises(TypeError):
228
            print(F())  # because barter is abstract now
229
        assert isabstract(F)
230
231
232
def test_abstractmethod_integration_namespaced(abc, namespace):
233
    for abstractthing in [abstractmethod, abc_main.abstractproperty,
234
                          abc_main.abstractclassmethod,
235
                          abc_main.abstractstaticmethod]:
236
        class C(metaclass=abc.NamespaceableABCMeta):
237
            with namespace() as ns:
238
                @abstractthing
239
                def footer(self):
240
                    pass  # abstract
241
242
                def barter(self):
243
                    pass  # concrete
244
        assert C.__abstractmethods__ == {"ns.footer"}
245
        with pytest.raises(TypeError):
246
            print(C())  # because footer is abstract
247
        assert isabstract(C)
248
249
        class D(C):
250
            with namespace() as ns:
251
                def barter(self):
252
                    pass  # concrete override of concrete
253
        assert D.__abstractmethods__ == {"ns.footer"}
254
        with pytest.raises(TypeError):
255
            print(D())  # because footer is still abstract
256
        assert isabstract(D)
257
258
        class E(D):
259
            with namespace() as ns:
260
                def footer(self):
261
                    pass
262
        assert E.__abstractmethods__ == set()
263
        E()  # now footer is concrete, too
264
        assert not isabstract(E)
265
266
        class F(E):
267
            with namespace() as ns:
268
                @abstractthing
269
                def barter(self):
270
                    pass  # abstract override of concrete
271
        assert F.__abstractmethods__ == {"ns.barter"}
272
        with pytest.raises(TypeError):
273
            print(F())  # because barter is abstract now
274
        assert isabstract(F)
275
276
277
def test_descriptors_with_abstractmethod(abc):
278
    class C(metaclass=abc.NamespaceableABCMeta):
279
        @property
280
        @abstractmethod
281
        def footer(self):
282
            return 3
283
284
        @footer.setter
285
        @abstractmethod
286
        def footer(self, val):
287
            pass
288
    with pytest.raises(TypeError):
289
        print(C())
290
291
    class D(C):
292
        @C.footer.getter
293
        def footer(self):
294
            return super().footer
295
    with pytest.raises(TypeError):
296
        print(D())
297
298
    class E(D):
299
        @D.footer.setter
300
        def footer(self, val):
301
            pass
302
    assert E().footer == 3
303
    # check that the property's __isabstractmethod__ descriptor does the
304
    # right thing when presented with a value that fails truth testing:
305
306
    class NotBool(object):
307
        def __bool__(self):
308
            raise ValueError()
309
        __len__ = __bool__
310
    with pytest.raises(ValueError):
311
        class F(C):
312
            def barter(self):
313
                pass
314
            barter.__isabstractmethod__ = NotBool()
315
            footer = property(barter)
316
317
318
def test_descriptors_with_abstractmethod_namespaced(abc, namespace):
319
    class C(metaclass=abc.NamespaceableABCMeta):
320
        with namespace() as ns:
321
            @property
322
            @abstractmethod
323
            def footer(self):
324
                return 3
325
326
            @footer.setter
327
            @abstractmethod
328
            def footer(self, val):
329
                pass
330
    with pytest.raises(TypeError):
331
        print(C())
332
333
    class D(C):
334
        with namespace() as ns:
335
            @C.ns.footer.getter
336
            def footer(self):
337
                return super().ns.footer
338
    with pytest.raises(TypeError):
339
        print(D())
340
341
    class E(D):
342
        with namespace() as ns:
343
            @D.ns.footer.setter
344
            def footer(self, val):
345
                pass
346
    assert E().ns.footer == 3
347
    # check that the property's __isabstractmethod__ descriptor does the
348
    # right thing when presented with a value that fails truth testing:
349
350
    class NotBool(object):
351
        def __bool__(self):
352
            raise ValueError()
353
        __len__ = __bool__
354
    with pytest.raises(ValueError):
355
        class F(C):
356
            with namespace() as ns:
357
                def barter(self):
358
                    pass
359
                barter.__isabstractmethod__ = NotBool()
360
                footer = property(barter)
361
362
363
def test_customdescriptors_with_abstractmethod(abc):
364
    class Descriptor:
365
        def __init__(self, fget, fset=None):
366
            self._fget = fget
367
            self._fset = fset
368
369
        def getter(self, callable):
370
            return Descriptor(callable, self._fget)
371
372
        def setter(self, callable):
373
            return Descriptor(self._fget, callable)
374
375
        @property
376
        def __isabstractmethod__(self):
377
            return (getattr(self._fget, '__isabstractmethod__', False) or
378
                    getattr(self._fset, '__isabstractmethod__', False))
379
380
    class C(metaclass=abc.NamespaceableABCMeta):
381
        @Descriptor
382
        @abstractmethod
383
        def footer(self):
384
            return 3
385
386
        @footer.setter
387
        @abstractmethod
388
        def footer(self, val):
389
            pass
390
    with pytest.raises(TypeError):
391
        print(C())
392
393
    class D(C):
394
        @C.footer.getter
395
        def footer(self):
396
            return super().footer
397
    with pytest.raises(TypeError):
398
        print(D())
399
400
    class E(D):
401
        @D.footer.setter
402
        def footer(self, val):
403
            pass
404
    assert not (E.footer.__isabstractmethod__)
405
406
407
def test_customdescriptors_with_abstractmethod_namespaced(abc, namespace):
408
    class Descriptor:
409
        def __init__(self, fget, fset=None):
410
            self._fget = fget
411
            self._fset = fset
412
413
        def getter(self, callable):
414
            return Descriptor(callable, self._fget)
415
416
        def setter(self, callable):
417
            return Descriptor(self._fget, callable)
418
419
        @property
420
        def __isabstractmethod__(self):
421
            return (getattr(self._fget, '__isabstractmethod__', False) or
422
                    getattr(self._fset, '__isabstractmethod__', False))
423
424
    class C(metaclass=abc.NamespaceableABCMeta):
425
        with namespace() as ns:
426
            @Descriptor
427
            @abstractmethod
428
            def footer(self):
429
                return 3
430
431
            @footer.setter
432
            @abstractmethod
433
            def footer(self, val):
434
                pass
435
    with pytest.raises(TypeError):
436
        print(C())
437
438
    class D(C):
439
        with namespace() as ns:
440
            @C.ns.footer.getter
441
            def footer(self):
442
                return super().ns.footer
443
    with pytest.raises(TypeError):
444
        print(D())
445
446
    class E(D):
447
        with namespace() as ns:
448
            @D.ns.footer.setter
449
            def footer(self, val):
450
                pass
451
    assert not (E.ns.footer.__isabstractmethod__)
452
453
454
def test_metaclass_abc(abc):
455
    # Metaclasses can be ABCs, too.
456
    class A(metaclass=abc.NamespaceableABCMeta):
457
        @abstractmethod
458
        def x(self):
459
            pass
460
    assert A.__abstractmethods__ == {"x"}
461
462
    class meta(type, A):
463
        def x(self):
464
            return 1
465
466
    class C(metaclass=meta):
467
        pass
468
469
470
def test_metaclass_abc_namespaced(abc, namespace):
471
    # Metaclasses can be ABCs, too.
472
    class A(metaclass=abc.NamespaceableABCMeta):
473
        with namespace() as ns:
474
            @abstractmethod
475
            def x(self):
476
                pass
477
    assert A.__abstractmethods__ == {"ns.x"}
478
479
    class meta(type, A):
480
        with namespace() as ns:
481
            def x(self):
482
                return 1
483
484
    class C(metaclass=meta):
485
        pass
486
487
488
def test_registration_basics(abc):
489
    class A(metaclass=abc.NamespaceableABCMeta):
490
        pass
491
492
    class B(object):
493
        pass
494
    b = B()
495
    assert not (issubclass(B, A))
496
    assert not (issubclass(B, (A,)))
497
    assert not isinstance(b, A)
498
    assert not isinstance(b, (A,))
499
    B1 = A.register(B)
500
    assert issubclass(B, A)
501
    assert issubclass(B, (A,))
502
    assert isinstance(b, A)
503
    assert isinstance(b, (A,))
504
    assert B1 is B
505
506
    class C(B):
507
        pass
508
    c = C()
509
    assert issubclass(C, A)
510
    assert issubclass(C, (A,))
511
    assert isinstance(c, A)
512
    assert isinstance(c, (A,))
513
514
515
def test_register_as_class_deco(abc):
516
    class A(metaclass=abc.NamespaceableABCMeta):
517
        pass
518
519
    @A.register
520
    class B(object):
521
        pass
522
    b = B()
523
    assert issubclass(B, A)
524
    assert issubclass(B, (A,))
525
    assert isinstance(b, A)
526
    assert isinstance(b, (A,))
527
528
    @A.register
529
    class C(B):
530
        pass
531
    c = C()
532
    assert issubclass(C, A)
533
    assert issubclass(C, (A,))
534
    assert isinstance(c, A)
535
    assert isinstance(c, (A,))
536
    assert C is A.register(C)
537
538
539
@pytest.mark.xfail(sys.version_info < (3, 4),
540
                   reason="python3.4 api changes?", strict=True)
541
def test_isinstance_invalidation(abc):
542
    class A(metaclass=abc.NamespaceableABCMeta):
543
        pass
544
545
    class B:
546
        pass
547
    b = B()
548
    assert not (isinstance(b, A))
549
    assert not (isinstance(b, (A,)))
550
    token_old = abc_main.get_cache_token()
551
    A.register(B)
552
    token_new = abc_main.get_cache_token()
553
    assert token_old != token_new
554
    assert isinstance(b, A)
555
    assert isinstance(b, (A,))
556
557
558
def test_registration_builtins(abc):
559
    class A(metaclass=abc.NamespaceableABCMeta):
560
        pass
561
    A.register(int)
562
    assert isinstance(42, A)
563
    assert isinstance(42, (A,))
564
    assert issubclass(int, A)
565
    assert issubclass(int, (A,))
566
567
    class B(A):
568
        pass
569
    B.register(str)
570
571
    class C(str):
572
        pass
573
    assert isinstance("", A)
574
    assert isinstance("", (A,))
575
    assert issubclass(str, A)
576
    assert issubclass(str, (A,))
577
    assert issubclass(C, A)
578
    assert issubclass(C, (A,))
579
580
581
def test_registration_edge_cases(abc):
582
    class A(metaclass=abc.NamespaceableABCMeta):
583
        pass
584
    A.register(A)  # should pass silently
585
586
    class A1(A):
587
        pass
588
    with pytest.raises(RuntimeError):
589
        A1.register(A)  # cycles not allowed
590
591
    class B(object):
592
        pass
593
    A1.register(B)  # ok
594
    A1.register(B)  # should pass silently
595
596
    class C(A):
597
        pass
598
    A.register(C)  # should pass silently
599
    with pytest.raises(RuntimeError):
600
        C.register(A)  # cycles not allowed
601
    C.register(B)  # ok
602
603
604
def test_register_non_class(abc):
605
    class A(metaclass=abc.NamespaceableABCMeta):
606
        pass
607
    with pytest.raises(TypeError, message="Can only register classes"):
608
        print(A.register(4))
609
610
611
def test_registration_transitiveness(abc):
612
    class A(metaclass=abc.NamespaceableABCMeta):
613
        pass
614
    assert issubclass(A, A)
615
    assert issubclass(A, (A,))
616
617
    class B(metaclass=abc.NamespaceableABCMeta):
618
        pass
619
    assert not (issubclass(A, B))
620
    assert not (issubclass(A, (B,)))
621
    assert not (issubclass(B, A))
622
    assert not (issubclass(B, (A,)))
623
624
    class C(metaclass=abc.NamespaceableABCMeta):
625
        pass
626
    A.register(B)
627
628
    class B1(B):
629
        pass
630
    assert issubclass(B1, A)
631
    assert issubclass(B1, (A,))
632
633
    class C1(C):
634
        pass
635
    B1.register(C1)
636
    assert not issubclass(C, B)
637
    assert not issubclass(C, (B,))
638
    assert not issubclass(C, B1)
639
    assert not issubclass(C, (B1,))
640
    assert issubclass(C1, A)
641
    assert issubclass(C1, (A,))
642
    assert issubclass(C1, B)
643
    assert issubclass(C1, (B,))
644
    assert issubclass(C1, B1)
645
    assert issubclass(C1, (B1,))
646
    C1.register(int)
647
648
    class MyInt(int):
649
        pass
650
    assert issubclass(MyInt, A)
651
    assert issubclass(MyInt, (A,))
652
    assert isinstance(42, A)
653
    assert isinstance(42, (A,))
654
655
656
def test_all_new_methods_are_called(abc):
657
    class A(metaclass=abc.NamespaceableABCMeta):
658
        pass
659
660
    class B(object):
661
        counter = 0
662
663
        def __new__(cls):
664
            B.counter += 1
665
            return super().__new__(cls)
666
667
    class C(A, B):
668
        pass
669
    assert B.counter == 0
670
    C()
671
    assert B.counter == 1
672