Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/cryptography/utils.py: 73%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x 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.
5from __future__ import annotations
7import enum
8import sys
9import types
10import typing
11import warnings
12from collections.abc import Sequence
15# We use a UserWarning subclass, instead of DeprecationWarning, because CPython
16# decided deprecation warnings should be invisible by default.
17class CryptographyDeprecationWarning(UserWarning):
18 pass
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.
24DeprecatedIn36 = CryptographyDeprecationWarning
25DeprecatedIn40 = CryptographyDeprecationWarning
26DeprecatedIn41 = CryptographyDeprecationWarning
27DeprecatedIn42 = CryptographyDeprecationWarning
28DeprecatedIn43 = CryptographyDeprecationWarning
29DeprecatedIn47 = CryptographyDeprecationWarning
30DeprecatedIn50 = CryptographyDeprecationWarning
31DeprecatedIn51 = CryptographyDeprecationWarning
34# If you're wondering why we don't use `Buffer`, it's because `Buffer` would
35# be more accurately named: Bufferable. It means something which has an
36# `__buffer__`. Which means you can't actually treat the result as a buffer
37# (and do things like take a `len()`).
38Buffer = typing.Union[bytes, bytearray, memoryview]
41def _check_bytes(name: str, value: bytes) -> None:
42 if not isinstance(value, bytes):
43 raise TypeError(f"{name} must be bytes")
46def _check_byteslike(name: str, value: Buffer) -> None:
47 if isinstance(value, (bytes, bytearray, memoryview)):
48 return
49 try:
50 memoryview(value)
51 except TypeError:
52 raise TypeError(f"{name} must be bytes-like")
55def int_to_bytes(integer: int, length: int | None = None) -> bytes:
56 if length == 0:
57 raise ValueError("length argument can't be 0")
58 return integer.to_bytes(
59 length or (integer.bit_length() + 7) // 8 or 1, "big"
60 )
63class InterfaceNotImplemented(Exception):
64 pass
67class _DeprecatedValue:
68 def __init__(self, value: object, message: str, warning_class):
69 self.value = value
70 self.message = message
71 self.warning_class = warning_class
74class _ModuleWithDeprecations(types.ModuleType):
75 def __init__(self, module: types.ModuleType):
76 super().__init__(module.__name__)
77 self.__dict__["_module"] = module
79 def __getattr__(self, name: str) -> typing.Any:
80 obj = getattr(self._module, name)
81 if isinstance(obj, _DeprecatedValue):
82 warnings.warn(obj.message, obj.warning_class, stacklevel=2)
83 obj = obj.value
84 else:
85 # Cache non-deprecated attributes in our own `__dict__` so that
86 # subsequent lookups are ordinary module attribute accesses and
87 # don't pay for this `__getattr__` (which would otherwise defeat
88 # CPython's LOAD_ATTR module caching for every attribute of the
89 # module). `__setattr__` and `__delattr__` keep the cache
90 # coherent.
91 self.__dict__[name] = obj
92 return obj
94 def __setattr__(self, attr: str, value: object) -> None:
95 if isinstance(value, _DeprecatedValue):
96 self.__dict__.pop(attr, None)
97 else:
98 self.__dict__[attr] = value
99 setattr(self._module, attr, value)
101 def __delattr__(self, attr: str) -> None:
102 obj = getattr(self._module, attr)
103 if isinstance(obj, _DeprecatedValue):
104 warnings.warn(obj.message, obj.warning_class, stacklevel=2)
106 self.__dict__.pop(attr, None)
107 delattr(self._module, attr)
109 def __dir__(self) -> Sequence[str]:
110 return ["_module", *dir(self._module)]
113def deprecated(
114 value: object,
115 module_name: str,
116 message: str,
117 warning_class: type[Warning],
118 name: str | None = None,
119) -> _DeprecatedValue:
120 module = sys.modules[module_name]
121 if not isinstance(module, _ModuleWithDeprecations):
122 sys.modules[module_name] = module = _ModuleWithDeprecations(module)
123 dv = _DeprecatedValue(value, message, warning_class)
124 # Maintain backwards compatibility with `name is None` for pyOpenSSL.
125 if name is not None:
126 setattr(module, name, dv)
127 return dv
130# Python 3.10 changed representation of enums. We use well-defined object
131# representation and string representation from Python 3.9.
132class Enum(enum.Enum):
133 def __repr__(self) -> str:
134 return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>"
136 def __str__(self) -> str:
137 return f"{self.__class__.__name__}.{self._name_}"