Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/compat.py: 62%
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"""
6Python 2 and 3 link classes.
7"""
9import base64
10import binascii
11import struct
12import sys
14from typing import (
15 Any,
16 AnyStr,
17 Callable,
18 Optional,
19 TypeVar,
20 TYPE_CHECKING,
21 Union,
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 'orb',
40 'plain_str',
41 'raw',
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.12), 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")
103###########
104# Python3 #
105###########
107# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
108DecoratorCallable = TypeVar("DecoratorCallable", bound=Callable[..., Any])
111# This is ugly, but we don't want to move raw() out of compat.py
112# and it makes it much clearer
113if TYPE_CHECKING:
114 from scapy.packet import Packet
117def raw(x):
118 # type: (Packet) -> bytes
119 """
120 Builds a packet and returns its bytes representation.
121 This function is and will always be cross-version compatible
122 """
123 return bytes(x)
126def bytes_encode(x):
127 # type: (Any) -> bytes
128 """Ensure that the given object is bytes. If the parameter is a
129 packet, raw() should be preferred.
131 """
132 if isinstance(x, str):
133 return x.encode()
134 return bytes(x)
137def plain_str(x):
138 # type: (Any) -> str
139 """Convert basic byte objects to str"""
140 if isinstance(x, bytes):
141 return x.decode(errors="backslashreplace")
142 return str(x)
145def chb(x):
146 # type: (int) -> bytes
147 """Same than chr() but encode as bytes."""
148 return struct.pack("!B", x)
151def orb(x):
152 # type: (Union[int, str, bytes]) -> int
153 """Return ord(x) when not already an int."""
154 if isinstance(x, int):
155 return x
156 return ord(x)
159def bytes_hex(x):
160 # type: (AnyStr) -> bytes
161 """Hexify a str or a bytes object"""
162 return binascii.b2a_hex(bytes_encode(x))
165def hex_bytes(x):
166 # type: (AnyStr) -> bytes
167 """De-hexify a str or a byte object"""
168 return binascii.a2b_hex(bytes_encode(x))
171def int_bytes(x, size):
172 # type: (int, int) -> bytes
173 """Convert an int to an arbitrary sized bytes string"""
174 return x.to_bytes(size, byteorder='big')
177def bytes_int(x):
178 # type: (bytes) -> int
179 """Convert an arbitrary sized bytes string to an int"""
180 return int.from_bytes(x, "big")
183def base64_bytes(x):
184 # type: (AnyStr) -> bytes
185 """Turn base64 into bytes"""
186 return base64.decodebytes(bytes_encode(x))
189def bytes_base64(x):
190 # type: (AnyStr) -> bytes
191 """Turn bytes into base64"""
192 return base64.encodebytes(bytes_encode(x)).replace(b'\n', b'')