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 dual licensed under the terms of the Apache License, Version 

2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 

3# for complete details. 

4 

5 

6import abc 

7import inspect 

8import sys 

9import typing 

10import warnings 

11 

12 

13# We use a UserWarning subclass, instead of DeprecationWarning, because CPython 

14# decided deprecation warnings should be invisble by default. 

15class CryptographyDeprecationWarning(UserWarning): 

16 pass 

17 

18 

19# Several APIs were deprecated with no specific end-of-life date because of the 

20# ubiquity of their use. They should not be removed until we agree on when that 

21# cycle ends. 

22PersistentlyDeprecated2017 = CryptographyDeprecationWarning 

23PersistentlyDeprecated2019 = CryptographyDeprecationWarning 

24DeprecatedIn34 = CryptographyDeprecationWarning 

25 

26 

27def _check_bytes(name: str, value: bytes): 

28 if not isinstance(value, bytes): 

29 raise TypeError("{} must be bytes".format(name)) 

30 

31 

32def _check_byteslike(name: str, value: bytes): 

33 try: 

34 memoryview(value) 

35 except TypeError: 

36 raise TypeError("{} must be bytes-like".format(name)) 

37 

38 

39def read_only_property(name: str): 

40 return property(lambda self: getattr(self, name)) 

41 

42 

43def register_interface(iface): 

44 def register_decorator(klass, *, check_annotations=False): 

45 verify_interface(iface, klass, check_annotations=check_annotations) 

46 iface.register(klass) 

47 return klass 

48 

49 return register_decorator 

50 

51 

52def register_interface_if(predicate, iface): 

53 def register_decorator(klass, *, check_annotations=False): 

54 if predicate: 

55 verify_interface(iface, klass, check_annotations=check_annotations) 

56 iface.register(klass) 

57 return klass 

58 

59 return register_decorator 

60 

61 

62def int_to_bytes(integer: int, length: typing.Optional[int] = None) -> bytes: 

63 return integer.to_bytes( 

64 length or (integer.bit_length() + 7) // 8 or 1, "big" 

65 ) 

66 

67 

68class InterfaceNotImplemented(Exception): 

69 pass 

70 

71 

72def strip_annotation(signature): 

73 return inspect.Signature( 

74 [ 

75 param.replace(annotation=inspect.Parameter.empty) 

76 for param in signature.parameters.values() 

77 ] 

78 ) 

79 

80 

81def verify_interface(iface, klass, *, check_annotations=False): 

82 for method in iface.__abstractmethods__: 

83 if not hasattr(klass, method): 

84 raise InterfaceNotImplemented( 

85 "{} is missing a {!r} method".format(klass, method) 

86 ) 

87 if isinstance(getattr(iface, method), abc.abstractproperty): 

88 # Can't properly verify these yet. 

89 continue 

90 sig = inspect.signature(getattr(iface, method)) 

91 actual = inspect.signature(getattr(klass, method)) 

92 if check_annotations: 

93 ok = sig == actual 

94 else: 

95 ok = strip_annotation(sig) == strip_annotation(actual) 

96 if not ok: 

97 raise InterfaceNotImplemented( 

98 "{}.{}'s signature differs from the expected. Expected: " 

99 "{!r}. Received: {!r}".format(klass, method, sig, actual) 

100 ) 

101 

102 

103class _DeprecatedValue(object): 

104 def __init__(self, value, message, warning_class): 

105 self.value = value 

106 self.message = message 

107 self.warning_class = warning_class 

108 

109 

110class _ModuleWithDeprecations(object): 

111 def __init__(self, module): 

112 self.__dict__["_module"] = module 

113 

114 def __getattr__(self, attr): 

115 obj = getattr(self._module, attr) 

116 if isinstance(obj, _DeprecatedValue): 

117 warnings.warn(obj.message, obj.warning_class, stacklevel=2) 

118 obj = obj.value 

119 return obj 

120 

121 def __setattr__(self, attr, value): 

122 setattr(self._module, attr, value) 

123 

124 def __delattr__(self, attr): 

125 obj = getattr(self._module, attr) 

126 if isinstance(obj, _DeprecatedValue): 

127 warnings.warn(obj.message, obj.warning_class, stacklevel=2) 

128 

129 delattr(self._module, attr) 

130 

131 def __dir__(self): 

132 return ["_module"] + dir(self._module) 

133 

134 

135def deprecated(value, module_name, message, warning_class): 

136 module = sys.modules[module_name] 

137 if not isinstance(module, _ModuleWithDeprecations): 

138 sys.modules[module_name] = _ModuleWithDeprecations( 

139 module 

140 ) # type: ignore[assignment] 

141 return _DeprecatedValue(value, message, warning_class) 

142 

143 

144def cached_property(func): 

145 cached_name = "_cached_{}".format(func) 

146 sentinel = object() 

147 

148 def inner(instance): 

149 cache = getattr(instance, cached_name, sentinel) 

150 if cache is not sentinel: 

151 return cache 

152 result = func(instance) 

153 setattr(instance, cached_name, result) 

154 return result 

155 

156 return property(inner) 

157 

158 

159int_from_bytes = deprecated( 

160 int.from_bytes, 

161 __name__, 

162 "int_from_bytes is deprecated, use int.from_bytes instead", 

163 DeprecatedIn34, 

164)