Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/utils.py: 68%
71 statements
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-14 06:36 +0000
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-14 06:36 +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.
6import enum
7import sys
8import types
9import typing
10import warnings
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
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.
22DeprecatedIn36 = CryptographyDeprecationWarning
23DeprecatedIn37 = CryptographyDeprecationWarning
24DeprecatedIn39 = CryptographyDeprecationWarning
25DeprecatedIn40 = CryptographyDeprecationWarning
28def _check_bytes(name: str, value: bytes) -> None:
29 if not isinstance(value, bytes):
30 raise TypeError(f"{name} must be bytes")
33def _check_byteslike(name: str, value: bytes) -> None:
34 try:
35 memoryview(value)
36 except TypeError:
37 raise TypeError(f"{name} must be bytes-like")
40def int_to_bytes(integer: int, length: typing.Optional[int] = None) -> bytes:
41 return integer.to_bytes(
42 length or (integer.bit_length() + 7) // 8 or 1, "big"
43 )
46class InterfaceNotImplemented(Exception):
47 pass
50class _DeprecatedValue:
51 def __init__(self, value: object, message: str, warning_class):
52 self.value = value
53 self.message = message
54 self.warning_class = warning_class
57class _ModuleWithDeprecations(types.ModuleType):
58 def __init__(self, module: types.ModuleType):
59 super().__init__(module.__name__)
60 self.__dict__["_module"] = module
62 def __getattr__(self, attr: str) -> object:
63 obj = getattr(self._module, attr)
64 if isinstance(obj, _DeprecatedValue):
65 warnings.warn(obj.message, obj.warning_class, stacklevel=2)
66 obj = obj.value
67 return obj
69 def __setattr__(self, attr: str, value: object) -> None:
70 setattr(self._module, attr, value)
72 def __delattr__(self, attr: str) -> None:
73 obj = getattr(self._module, attr)
74 if isinstance(obj, _DeprecatedValue):
75 warnings.warn(obj.message, obj.warning_class, stacklevel=2)
77 delattr(self._module, attr)
79 def __dir__(self) -> typing.Sequence[str]:
80 return ["_module"] + dir(self._module)
83def deprecated(
84 value: object,
85 module_name: str,
86 message: str,
87 warning_class: typing.Type[Warning],
88 name: typing.Optional[str] = None,
89) -> _DeprecatedValue:
90 module = sys.modules[module_name]
91 if not isinstance(module, _ModuleWithDeprecations):
92 sys.modules[module_name] = module = _ModuleWithDeprecations(module)
93 dv = _DeprecatedValue(value, message, warning_class)
94 # Maintain backwards compatibility with `name is None` for pyOpenSSL.
95 if name is not None:
96 setattr(module, name, dv)
97 return dv
100def cached_property(func: typing.Callable) -> property:
101 cached_name = f"_cached_{func}"
102 sentinel = object()
104 def inner(instance: object):
105 cache = getattr(instance, cached_name, sentinel)
106 if cache is not sentinel:
107 return cache
108 result = func(instance)
109 setattr(instance, cached_name, result)
110 return result
112 return property(inner)
115# Python 3.10 changed representation of enums. We use well-defined object
116# representation and string representation from Python 3.9.
117class Enum(enum.Enum):
118 def __repr__(self) -> str:
119 return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>"
121 def __str__(self) -> str:
122 return f"{self.__class__.__name__}.{self._name_}"