Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/compat.py: 59%
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# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
5"""
6Compatibility module to various older versions of Python
7"""
9import base64
10import binascii
11import enum
12import struct
13import sys
15from typing import (
16 Any,
17 AnyStr,
18 Callable,
19 Optional,
20 TypeVar,
21 TYPE_CHECKING,
22)
24# Very important: will issue typing errors otherwise
25__all__ = [
26 # typing
27 'DecoratorCallable',
28 'Literal',
29 'Protocol',
30 'Self',
31 'UserDict',
32 # compat
33 'base64_bytes',
34 'bytes_base64',
35 'bytes_encode',
36 'bytes_hex',
37 'chb',
38 'hex_bytes',
39 'plain_str',
40 'raw',
41 'StrEnum',
42]
44# Typing compatibility
46# Note:
47# supporting typing on multiple python versions is a nightmare.
48# we provide a FakeType class to be able to use types added on
49# later Python versions (since we run mypy on 3.14), on older
50# ones.
53# Import or create fake types
55def _FakeType(name, cls=object):
56 # type: (str, Optional[type]) -> Any
57 class _FT(object):
58 def __init__(self, name):
59 # type: (str) -> None
60 self.name = name
62 # make the objects subscriptable indefinitely
63 def __getitem__(self, item): # type: ignore
64 return cls
66 def __call__(self, *args, **kargs):
67 # type: (*Any, **Any) -> Any
68 if isinstance(args[0], str):
69 self.name = args[0]
70 return self
72 def __repr__(self):
73 # type: () -> str
74 return "<Fake typing.%s>" % self.name
75 return _FT(name)
78# Python 3.8 Only
79if sys.version_info >= (3, 8):
80 from typing import Literal
81 from typing import Protocol
82else:
83 Literal = _FakeType("Literal")
85 class Protocol:
86 pass
89# Python 3.9 Only
90if sys.version_info >= (3, 9):
91 from collections import UserDict
92else:
93 from collections import UserDict as _UserDict
94 UserDict = _FakeType("_UserDict", _UserDict)
97# Python 3.11 Only
98if sys.version_info >= (3, 11):
99 from typing import Self
100else:
101 Self = _FakeType("Self")
104# Python 3.11 Only
105if sys.version_info >= (3, 11):
106 from enum import StrEnum
107else:
108 class StrEnum(str, enum.Enum):
109 pass
112###########
113# Python3 #
114###########
116# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
117DecoratorCallable = TypeVar("DecoratorCallable", bound=Callable[..., Any])
120# This is ugly, but we don't want to move raw() out of compat.py
121# and it makes it much clearer
122if TYPE_CHECKING:
123 from scapy.packet import Packet
126def raw(x):
127 # type: (Packet) -> bytes
128 """
129 Builds a packet and returns its bytes representation.
130 This function is and will always be cross-version compatible
131 """
132 return bytes(x)
135def bytes_encode(x):
136 # type: (Any) -> bytes
137 """Ensure that the given object is bytes. If the parameter is a
138 packet, raw() should be preferred.
140 """
141 if isinstance(x, str):
142 return x.encode()
143 return bytes(x)
146def plain_str(x):
147 # type: (Any) -> str
148 """Convert basic byte objects to str"""
149 if isinstance(x, bytes):
150 return x.decode(errors="backslashreplace")
151 return str(x)
154def chb(x):
155 # type: (int) -> bytes
156 """Same than chr() but encode as bytes."""
157 return struct.pack("!B", x)
160def bytes_hex(x):
161 # type: (AnyStr) -> bytes
162 """Hexify a str or a bytes object"""
163 return binascii.b2a_hex(bytes_encode(x))
166def hex_bytes(x):
167 # type: (AnyStr) -> bytes
168 """De-hexify a str or a byte object"""
169 return binascii.a2b_hex(bytes_encode(x))
172def int_bytes(x, size):
173 # type: (int, int) -> bytes
174 """Convert an int to an arbitrary sized bytes string"""
175 return x.to_bytes(size, byteorder='big')
178def bytes_int(x):
179 # type: (bytes) -> int
180 """Convert an arbitrary sized bytes string to an int"""
181 return int.from_bytes(x, "big")
184def base64_bytes(x):
185 # type: (AnyStr) -> bytes
186 """Turn base64 into bytes"""
187 return base64.decodebytes(bytes_encode(x))
190def bytes_base64(x):
191 # type: (AnyStr) -> bytes
192 """Turn bytes into base64"""
193 return base64.encodebytes(bytes_encode(x)).replace(b'\n', b'')