1from collections import deque 2import unittest 3from test.support import NEVER_EQ 4 5 6class base_set: 7 def __init__(self, el): 8 self.el = el 9 10class myset(base_set): 11 def __contains__(self, el): 12 return self.el == el 13 14class seq(base_set): 15 def __getitem__(self, n): 16 return [self.el][n] 17 18class TestContains(unittest.TestCase): 19 def test_common_tests(self): 20 a = base_set(1) 21 b = myset(1) 22 c = seq(1) 23 self.assertIn(1, b) 24 self.assertNotIn(0, b) 25 self.assertIn(1, c) 26 self.assertNotIn(0, c) 27 self.assertRaises(TypeError, lambda: 1 in a) 28 self.assertRaises(TypeError, lambda: 1 not in a) 29 30 # test char in string 31 self.assertIn('c', 'abc') 32 self.assertNotIn('d', 'abc') 33 34 self.assertIn('', '') 35 self.assertIn('', 'abc') 36 37 self.assertRaises(TypeError, lambda: None in 'abc') 38 39 def test_builtin_sequence_types(self): 40 # a collection of tests on builtin sequence types 41 a = range(10) 42 for i in a: 43 self.assertIn(i, a) 44 self.assertNotIn(16, a) 45 self.assertNotIn(a, a) 46 47 a = tuple(a) 48 for i in a: 49 self.assertIn(i, a) 50 self.assertNotIn(16, a) 51 self.assertNotIn(a, a) 52 53 class Deviant1: 54 """Behaves strangely when compared 55 56 This class is designed to make sure that the contains code 57 works when the list is modified during the check. 58 """ 59 aList = list(range(15)) 60 def __eq__(self, other): 61 if other == 12: 62 self.aList.remove(12) 63 self.aList.remove(13) 64 self.aList.remove(14) 65 return 0 66 67 self.assertNotIn(Deviant1(), Deviant1.aList) 68 69 def test_nonreflexive(self): 70 # containment and equality tests involving elements that are 71 # not necessarily equal to themselves 72 73 values = float('nan'), 1, None, 'abc', NEVER_EQ 74 constructors = list, tuple, dict.fromkeys, set, frozenset, deque 75 for constructor in constructors: 76 container = constructor(values) 77 for elem in container: 78 self.assertIn(elem, container) 79 self.assertTrue(container == constructor(values)) 80 self.assertTrue(container == container) 81 82 def test_block_fallback(self): 83 # blocking fallback with __contains__ = None 84 class ByContains(object): 85 def __contains__(self, other): 86 return False 87 c = ByContains() 88 class BlockContains(ByContains): 89 """Is not a container 90 91 This class is a perfectly good iterable (as tested by 92 list(bc)), as well as inheriting from a perfectly good 93 container, but __contains__ = None prevents the usual 94 fallback to iteration in the container protocol. That 95 is, normally, 0 in bc would fall back to the equivalent 96 of any(x==0 for x in bc), but here it's blocked from 97 doing so. 98 """ 99 def __iter__(self): 100 while False: 101 yield None 102 __contains__ = None 103 bc = BlockContains() 104 self.assertFalse(0 in c) 105 self.assertFalse(0 in list(bc)) 106 self.assertRaises(TypeError, lambda: 0 in bc) 107 108if __name__ == '__main__': 109 unittest.main() 110