Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of utils. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# Use of this source code is governed by a 3-clause BSD-style 

10# license that can be found in the LICENSE file. 

11 

12import unittest 

13import logging 

14import functools 

15import copy 

16import pickle 

17 

18from lsst.utils.classes import Singleton, immutable, cached_getter 

19 

20log = logging.getLogger("test_classes") 

21 

22 

23class SingletonTestCase(unittest.TestCase): 

24 """Tests of the Singleton metaclass""" 

25 

26 class IsSingleton(metaclass=Singleton): 

27 def __init__(self): 

28 self.data = {} 

29 self.id = 0 

30 

31 class IsBadSingleton(IsSingleton): 

32 def __init__(self, arg): 

33 """A singleton can not accept any arguments.""" 

34 self.arg = arg 

35 

36 class IsSingletonSubclass(IsSingleton): 

37 def __init__(self): 

38 super().__init__() 

39 

40 def testSingleton(self): 

41 one = SingletonTestCase.IsSingleton() 

42 two = SingletonTestCase.IsSingleton() 

43 

44 # Now update the first one and check the second 

45 one.data["test"] = 52 

46 self.assertEqual(one.data, two.data) 

47 two.id += 1 

48 self.assertEqual(one.id, two.id) 

49 

50 three = SingletonTestCase.IsSingletonSubclass() 

51 self.assertNotEqual(one.id, three.id) 

52 

53 with self.assertRaises(TypeError): 

54 SingletonTestCase.IsBadSingleton(52) 

55 

56 

57class ImmutabilityTestCase(unittest.TestCase): 

58 

59 @immutable 

60 class Immutable: 

61 

62 def __init__(self, name: str, number: int): 

63 self.name = name 

64 self.number = number 

65 

66 def __hash__(self) -> int: 

67 return hash((self.name, self.number)) 

68 

69 def testImmutable(self): 

70 im1 = ImmutabilityTestCase.Immutable("name", 42) 

71 im2 = ImmutabilityTestCase.Immutable("another", 0) 

72 self.assertEqual((im1.name, im1.number), ("name", 42)) 

73 test_set = {im1, im2} 

74 self.assertIn(im2, test_set) 

75 

76 with self.assertRaises(AttributeError): 

77 im1.name = "no" 

78 

79 self.assertIs(copy.copy(im1), im1) 

80 

81 # Pickling does not work without help and this tests that it 

82 # does not work. 

83 pickled = pickle.dumps(im1) 

84 im3 = pickle.loads(pickled) 

85 self.assertEqual(im3.__dict__, {}) 

86 

87 

88class CacheTestCase(unittest.TestCase): 

89 

90 class Cached1: 

91 """Cached getter using cached_getter. This can use slots.""" 

92 __slots__ = ("value", "_cached_cache_value") 

93 

94 def __init__(self, value: int): 

95 self.value = value 

96 

97 @property 

98 @cached_getter 

99 def cache_value(self) -> int: 

100 log.info("Calculating cached value.") 

101 return self.value + 1 

102 

103 class Cached2: 

104 """Cached getter using functools. This can not use slots.""" 

105 

106 def __init__(self, value: int): 

107 self.value = value 

108 

109 @functools.cached_property 

110 def cache_value(self) -> int: 

111 log.info("Calculating cached value.") 

112 return self.value + 1 

113 

114 def assertCache(self, cls): 

115 v1 = cls(42) 

116 self.assertEqual(v1.value, 42) 

117 

118 with self.assertLogs(level=logging.INFO) as cm: 

119 cached_value = v1.cache_value 

120 self.assertEqual(cached_value, 43) 

121 self.assertEqual(cm.output, ["INFO:test_classes:Calculating cached value."]) 

122 

123 v1.value = 50 

124 self.assertEqual(v1.value, 50) 

125 with self.assertLogs(level=logging.INFO) as cm: 

126 cached_value = v1.cache_value 

127 log.info("Used cache.") 

128 self.assertEqual(cached_value, 43) 

129 self.assertEqual(cm.output, ["INFO:test_classes:Used cache."]) 

130 

131 def testCachedGetter(self): 

132 self.assertCache(CacheTestCase.Cached1) 

133 

134 def testFunctoolsCachedProperty(self): 

135 self.assertCache(CacheTestCase.Cached2) 

136 

137 

138if __name__ == "__main__": 138 ↛ 139line 138 didn't jump to line 139, because the condition on line 138 was never true

139 unittest.main()