Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/utils.py: 56%

89 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

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 enum 

8import inspect 

9import sys 

10import types 

11import typing 

12import warnings 

13 

14 

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

16# decided deprecation warnings should be invisble by default. 

17class CryptographyDeprecationWarning(UserWarning): 

18 pass 

19 

20 

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

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

23# cycle ends. 

24PersistentlyDeprecated2019 = CryptographyDeprecationWarning 

25DeprecatedIn35 = CryptographyDeprecationWarning 

26DeprecatedIn36 = CryptographyDeprecationWarning 

27DeprecatedIn37 = CryptographyDeprecationWarning 

28DeprecatedIn38 = CryptographyDeprecationWarning 

29 

30 

31def _check_bytes(name: str, value: bytes) -> None: 

32 if not isinstance(value, bytes): 

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

34 

35 

36def _check_byteslike(name: str, value: bytes) -> None: 

37 try: 

38 memoryview(value) 

39 except TypeError: 

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

41 

42 

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

44 return integer.to_bytes( 

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

46 ) 

47 

48 

49class InterfaceNotImplemented(Exception): 

50 pass 

51 

52 

53def strip_annotation(signature: inspect.Signature) -> inspect.Signature: 

54 return inspect.Signature( 

55 [ 

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

57 for param in signature.parameters.values() 

58 ] 

59 ) 

60 

61 

62def verify_interface( 

63 iface: abc.ABCMeta, klass: object, *, check_annotations: bool = False 

64): 

65 for method in iface.__abstractmethods__: 

66 if not hasattr(klass, method): 

67 raise InterfaceNotImplemented( 

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

69 ) 

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

71 # Can't properly verify these yet. 

72 continue 

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

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

75 if check_annotations: 

76 ok = sig == actual 

77 else: 

78 ok = strip_annotation(sig) == strip_annotation(actual) 

79 if not ok: 

80 raise InterfaceNotImplemented( 

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

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

83 ) 

84 

85 

86class _DeprecatedValue: 

87 def __init__(self, value: object, message: str, warning_class): 

88 self.value = value 

89 self.message = message 

90 self.warning_class = warning_class 

91 

92 

93class _ModuleWithDeprecations(types.ModuleType): 

94 def __init__(self, module: types.ModuleType): 

95 super().__init__(module.__name__) 

96 self.__dict__["_module"] = module 

97 

98 def __getattr__(self, attr: str) -> object: 

99 obj = getattr(self._module, attr) 

100 if isinstance(obj, _DeprecatedValue): 

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

102 obj = obj.value 

103 return obj 

104 

105 def __setattr__(self, attr: str, value: object) -> None: 

106 setattr(self._module, attr, value) 

107 

108 def __delattr__(self, attr: str) -> None: 

109 obj = getattr(self._module, attr) 

110 if isinstance(obj, _DeprecatedValue): 

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

112 

113 delattr(self._module, attr) 

114 

115 def __dir__(self) -> typing.Sequence[str]: 

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

117 

118 

119def deprecated( 

120 value: object, 

121 module_name: str, 

122 message: str, 

123 warning_class: typing.Type[Warning], 

124 name: typing.Optional[str] = None, 

125) -> _DeprecatedValue: 

126 module = sys.modules[module_name] 

127 if not isinstance(module, _ModuleWithDeprecations): 

128 sys.modules[module_name] = module = _ModuleWithDeprecations(module) 

129 dv = _DeprecatedValue(value, message, warning_class) 

130 # Maintain backwards compatibility with `name is None` for pyOpenSSL. 

131 if name is not None: 

132 setattr(module, name, dv) 

133 return dv 

134 

135 

136def cached_property(func: typing.Callable) -> property: 

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

138 sentinel = object() 

139 

140 def inner(instance: object): 

141 cache = getattr(instance, cached_name, sentinel) 

142 if cache is not sentinel: 

143 return cache 

144 result = func(instance) 

145 setattr(instance, cached_name, result) 

146 return result 

147 

148 return property(inner) 

149 

150 

151# Python 3.10 changed representation of enums. We use well-defined object 

152# representation and string representation from Python 3.9. 

153class Enum(enum.Enum): 

154 def __repr__(self) -> str: 

155 return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>" 

156 

157 def __str__(self) -> str: 

158 return f"{self.__class__.__name__}.{self._name_}"