Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/dadict.py: 70%
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
4# Copyright (C) Philippe Biondi <phil@secdev.org>
6"""
7Direct Access dictionary.
8"""
10from scapy.error import Scapy_Exception
11from scapy.compat import plain_str
13# Typing
14from typing import (
15 Any,
16 Dict,
17 Generic,
18 Iterator,
19 List,
20 Tuple,
21 Type,
22 TypeVar,
23 Union,
24)
25from scapy.compat import Self
28###############################
29# Direct Access dictionary #
30###############################
33def fixname(x):
34 # type: (Union[bytes, str]) -> str
35 """
36 Modifies a string to make sure it can be used as an attribute name.
37 """
38 x = plain_str(x)
39 if x and str(x[0]) in "0123456789":
40 x = "n_" + x
41 return x.translate(
42 "________________________________________________"
43 "0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______"
44 "abcdefghijklmnopqrstuvwxyz____________________________"
45 "______________________________________________________"
46 "___________________________________________________"
47 )
50class DADict_Exception(Scapy_Exception):
51 pass
54_K = TypeVar('_K') # Key type
55_V = TypeVar('_V') # Value type
58class DADict(Generic[_K, _V]):
59 """
60 Direct Access Dictionary
62 This acts like a dict, but it provides a direct attribute access
63 to its keys through its values. This is used to store protocols,
64 manuf...
66 For instance, scapy fields will use a DADict as an enum::
68 ETHER_TYPES[2048] -> IPv4
70 Whereas humans can access::
72 ETHER_TYPES.IPv4 -> 2048
73 """
74 __slots__ = ["_name", "d"]
76 def __init__(self, _name="DADict", **kargs):
77 # type: (str, **Any) -> None
78 self._name = _name
79 self.d = {} # type: Dict[_K, _V]
80 self.update(kargs) # type: ignore
82 def ident(self, v):
83 # type: (_V) -> str
84 """
85 Return value that is used as key for the direct access
86 """
87 if isinstance(v, (str, bytes)):
88 return fixname(v)
89 return "unknown"
91 def update(self, *args, **kwargs):
92 # type: (*Dict[_K, _V], **Dict[_K, _V]) -> None
93 for k, v in dict(*args, **kwargs).items():
94 self[k] = v # type: ignore
96 def iterkeys(self):
97 # type: () -> Iterator[_K]
98 for x in self.d:
99 if not isinstance(x, str) or x[0] != "_":
100 yield x
102 def keys(self):
103 # type: () -> List[_K]
104 return list(self.iterkeys())
106 def __iter__(self):
107 # type: () -> Iterator[_K]
108 return self.iterkeys()
110 def itervalues(self):
111 # type: () -> Iterator[_V]
112 return self.d.values() # type: ignore
114 def values(self):
115 # type: () -> List[_V]
116 return list(self.itervalues())
118 def _show(self):
119 # type: () -> None
120 for k in self.iterkeys():
121 print("%10s = %r" % (k, self[k]))
123 def __repr__(self):
124 # type: () -> str
125 return "<%s - %s elements>" % (self._name, len(self))
127 def __getitem__(self, attr):
128 # type: (_K) -> _V
129 return self.d[attr]
131 def __setitem__(self, attr, val):
132 # type: (_K, _V) -> None
133 self.d[attr] = val
135 def __len__(self):
136 # type: () -> int
137 return len(self.d)
139 def __nonzero__(self):
140 # type: () -> bool
141 # Always has at least its name
142 return len(self) > 1
143 __bool__ = __nonzero__
145 def __getattr__(self, attr):
146 # type: (str) -> _K
147 try:
148 return object.__getattribute__(self, attr) # type: ignore
149 except AttributeError:
150 for k, v in self.d.items():
151 if self.ident(v) == attr:
152 return k
153 raise AttributeError
155 def __dir__(self):
156 # type: () -> List[str]
157 return [self.ident(x) for x in self.itervalues()]
159 def __reduce__(self):
160 # type: () -> Tuple[Type[Self], Tuple[str], Tuple[Dict[_K, _V]]]
161 return (self.__class__, (self._name,), (self.d,))
163 def __setstate__(self, state):
164 # type: (Tuple[Dict[_K, _V]]) -> Self
165 self.d.update(state[0])
166 return self