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