pypcapkit 1.0.3__cp310-none-any.whl → 1.1.0__cp310-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. pcapkit/__init__.py +1 -1
  2. pcapkit/const/pcapng/option_type.py +4 -1
  3. pcapkit/const/reg/apptype.py +19019 -19015
  4. pcapkit/corekit/fields/collections.py +14 -14
  5. pcapkit/corekit/fields/field.py +33 -8
  6. pcapkit/corekit/fields/ipaddress.py +0 -1
  7. pcapkit/corekit/fields/misc.py +14 -19
  8. pcapkit/corekit/fields/numbers.py +2 -3
  9. pcapkit/corekit/fields/strings.py +2 -3
  10. pcapkit/corekit/infoclass.py +59 -6
  11. pcapkit/corekit/protochain.py +8 -1
  12. pcapkit/foundation/registry/protocols.py +108 -16
  13. pcapkit/protocols/data/__init__.py +4 -4
  14. pcapkit/protocols/data/internet/__init__.py +4 -4
  15. pcapkit/protocols/data/internet/mh.py +8 -6
  16. pcapkit/protocols/data/transport/__init__.py +4 -4
  17. pcapkit/protocols/data/transport/tcp.py +4 -4
  18. pcapkit/protocols/internet/mh.py +21 -21
  19. pcapkit/protocols/protocol.py +3 -2
  20. pcapkit/protocols/schema/__init__.py +4 -4
  21. pcapkit/protocols/schema/application/httpv2.py +17 -33
  22. pcapkit/protocols/schema/internet/__init__.py +4 -4
  23. pcapkit/protocols/schema/internet/hip.py +62 -111
  24. pcapkit/protocols/schema/internet/hopopt.py +46 -48
  25. pcapkit/protocols/schema/internet/ipv4.py +36 -41
  26. pcapkit/protocols/schema/internet/ipv6_opts.py +48 -52
  27. pcapkit/protocols/schema/internet/ipv6_route.py +12 -21
  28. pcapkit/protocols/schema/internet/mh.py +57 -86
  29. pcapkit/protocols/schema/misc/pcapng.py +182 -193
  30. pcapkit/protocols/schema/schema.py +252 -53
  31. pcapkit/protocols/schema/transport/__init__.py +4 -4
  32. pcapkit/protocols/schema/transport/tcp.py +54 -81
  33. pcapkit/protocols/transport/tcp.py +14 -14
  34. pcapkit/vendor/pcapng/option_type.py +29 -2
  35. pcapkit/vendor/reg/apptype.py +34 -4
  36. {pypcapkit-1.0.3.dist-info → pypcapkit-1.1.0.dist-info}/METADATA +1 -1
  37. {pypcapkit-1.0.3.dist-info → pypcapkit-1.1.0.dist-info}/RECORD +41 -41
  38. {pypcapkit-1.0.3.dist-info → pypcapkit-1.1.0.dist-info}/LICENSE +0 -0
  39. {pypcapkit-1.0.3.dist-info → pypcapkit-1.1.0.dist-info}/WHEEL +0 -0
  40. {pypcapkit-1.0.3.dist-info → pypcapkit-1.1.0.dist-info}/entry_points.txt +0 -0
  41. {pypcapkit-1.0.3.dist-info → pypcapkit-1.1.0.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@
3
3
 
4
4
  import copy
5
5
  import io
6
- from typing import TYPE_CHECKING, TypeVar, cast
6
+ from typing import TYPE_CHECKING, Generic, TypeVar, cast
7
7
 
8
8
  from pcapkit.corekit.fields.field import _Field
9
9
  from pcapkit.corekit.multidict import OrderedMultiDict
@@ -25,9 +25,10 @@ if TYPE_CHECKING:
25
25
  from pcapkit.protocols.schema.schema import Schema
26
26
 
27
27
  _TL = TypeVar('_TL', 'Schema', '_Field', 'bytes')
28
+ _TS = TypeVar('_TS', bound='Schema')
28
29
 
29
30
 
30
- class ListField(_Field[List[_TL]]):
31
+ class ListField(_Field[List[_TL]], Generic[_TL]):
31
32
  """Field list for protocol fields.
32
33
 
33
34
  Args:
@@ -55,7 +56,7 @@ class ListField(_Field[List[_TL]]):
55
56
  def __init__(self, length: 'int | Callable[[dict[str, Any]], int]' = lambda _: -1,
56
57
  item_type: 'Optional[_Field]' = None,
57
58
  callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
58
- self._name = '<list>'
59
+ #self._name = '<list>'
59
60
  self._callback = callback
60
61
  self._item_type = item_type
61
62
 
@@ -74,9 +75,8 @@ class ListField(_Field[List[_TL]]):
74
75
  Returns:
75
76
  Updated field instance.
76
77
 
77
- Notes:
78
- This method will return a new instance of :class:`ListField`
79
- instead of updating the current instance.
78
+ This method will return a new instance of :class:`ListField`
79
+ instead of updating the current instance.
80
80
 
81
81
  """
82
82
  new_self = copy.copy(self)
@@ -160,7 +160,7 @@ class ListField(_Field[List[_TL]]):
160
160
  return temp
161
161
 
162
162
 
163
- class OptionField(ListField):
163
+ class OptionField(ListField, Generic[_TS]):
164
164
  """Field list for protocol options.
165
165
 
166
166
  Args:
@@ -181,7 +181,7 @@ class OptionField(ListField):
181
181
  """
182
182
 
183
183
  @property
184
- def base_schema(self) -> 'Type[Schema]':
184
+ def base_schema(self) -> 'Type[_TS]':
185
185
  """Base schema."""
186
186
  return self._base_schema
187
187
 
@@ -191,7 +191,7 @@ class OptionField(ListField):
191
191
  return self._type_name
192
192
 
193
193
  @property
194
- def registry(self) -> 'defaultdict[int | StdlibEnum | AenumEnum, Type[Schema]]':
194
+ def registry(self) -> 'defaultdict[int | StdlibEnum | AenumEnum, Type[_TS]]':
195
195
  """Option registry."""
196
196
  return self._registry
197
197
 
@@ -206,13 +206,13 @@ class OptionField(ListField):
206
206
  return self._option_padding
207
207
 
208
208
  def __init__(self, length: 'int | Callable[[dict[str, Any]], int]' = lambda _: -1,
209
- base_schema: 'Optional[Type[Schema]]' = None,
209
+ base_schema: 'Optional[Type[_TS]]' = None,
210
210
  type_name: 'str' = 'type',
211
- registry: 'Optional[defaultdict[int | StdlibEnum | AenumEnum, Type[Schema]]]' = None,
211
+ registry: 'Optional[defaultdict[int | StdlibEnum | AenumEnum, Type[_TS]]]' = None,
212
212
  eool: 'Optional[int | StdlibEnum | AenumEnum]' = None,
213
213
  callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
214
214
  super().__init__(length, None, callback)
215
- self._name = '<option>'
215
+ #self._name = '<option>'
216
216
  self._eool = eool
217
217
  self._option_padding = 0
218
218
 
@@ -228,7 +228,7 @@ class OptionField(ListField):
228
228
  raise FieldValueError('Field <option> has no registry.')
229
229
  self._registry = registry
230
230
 
231
- def unpack(self, buffer: 'bytes | IO[bytes]', packet: 'dict[str, Any]') -> 'list[Schema]':
231
+ def unpack(self, buffer: 'bytes | IO[bytes]', packet: 'dict[str, Any]') -> 'list[_TS]':
232
232
  """Unpack field value from :obj:`bytes`.
233
233
 
234
234
  Args:
@@ -256,7 +256,7 @@ class OptionField(ListField):
256
256
  new_packet = packet.copy()
257
257
  new_packet[self.name] = OrderedMultiDict()
258
258
 
259
- temp = [] # type: list[Schema]
259
+ temp = [] # type: list[_TS]
260
260
  while length > 0:
261
261
  # unpack option type using base schema
262
262
  meta = self._base_schema.unpack(file, length, packet) # type: ignore[call-arg,misc,var-annotated]
@@ -16,6 +16,8 @@ if TYPE_CHECKING:
16
16
 
17
17
  from typing_extensions import Literal, Self
18
18
 
19
+ from pcapkit.protocols.schema.schema import Schema
20
+
19
21
  _T = TypeVar('_T')
20
22
 
21
23
 
@@ -41,6 +43,10 @@ class _Field(Generic[_T], metaclass=abc.ABCMeta):
41
43
  :meth:`~_Field.pack` should be considerate of the template format
42
44
  and the actual value provided for packing.
43
45
 
46
+ Args:
47
+ *args: Arbitrary positional arguments.
48
+ **kwargs: Arbitrary keyword arguments.
49
+
44
50
  """
45
51
 
46
52
  if TYPE_CHECKING:
@@ -98,9 +104,8 @@ class _Field(Generic[_T], metaclass=abc.ABCMeta):
98
104
  Returns:
99
105
  Updated field instance.
100
106
 
101
- Notes:
102
- This method will return a new instance of :class:`_Field` instead of
103
- updating the current instance.
107
+ This method will return a new instance of :class:`_Field` instead of
108
+ updating the current instance.
104
109
 
105
110
  """
106
111
  new_self = copy.copy(self)
@@ -109,7 +114,9 @@ class _Field(Generic[_T], metaclass=abc.ABCMeta):
109
114
 
110
115
  # NOTE: This method is created as a placeholder for the necessary attributes.
111
116
  def __init__(self, *args: 'Any', **kwargs: 'Any') -> 'None':
112
- self._name = f'<{type(self).__name__[:-5].lower()}>'
117
+ if not hasattr(self, '_name'):
118
+ self._name = f'<{type(self).__name__[:-5].lower()}>'
119
+
113
120
  self._default = NoValue
114
121
  self._template = '0s'
115
122
  self._callback = lambda *_: None
@@ -119,6 +126,22 @@ class _Field(Generic[_T], metaclass=abc.ABCMeta):
119
126
  return f'<{self.__class__.__name__}>'
120
127
  return f'<{self.__class__.__name__} {self.name}>'
121
128
 
129
+ def __set_name__(self, owner: 'Schema', name: 'str') -> 'None':
130
+ """Set field name and update field list (if applicable).
131
+
132
+ This method is to be called by the metaclass during class creation.
133
+ It is used to set the field name and update the field list, i.e.,
134
+ :attr:`Schema.__fields__ <pcapkit.protocols.schema.schema.Schema.__fields__>`
135
+ mapping dictionary.
136
+
137
+ """
138
+ # Update field list (if applicable)
139
+ if hasattr(owner, '__fields__'):
140
+ owner.__fields__[name] = self
141
+
142
+ # Set field name
143
+ self.name = name
144
+
122
145
  def pre_process(self, value: '_T', packet: 'dict[str, Any]') -> 'Any': # pylint: disable=unused-argument
123
146
  """Process field value before construction (packing).
124
147
 
@@ -204,7 +227,10 @@ class Field(_Field[_T], Generic[_T]):
204
227
  def __init__(self, length: 'int | Callable[[dict[str, Any]], int]',
205
228
  default: '_T | NoValueType' = NoValue,
206
229
  callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
207
- self._name = '<unknown>'
230
+ #self._name = '<unknown>'
231
+ if not hasattr(self, '_name'):
232
+ self._name = f'<{type(self).__name__[:-5].lower()}>'
233
+
208
234
  self._default = default
209
235
  self._callback = callback
210
236
 
@@ -222,9 +248,8 @@ class Field(_Field[_T], Generic[_T]):
222
248
  Returns:
223
249
  New instance of :class:`Field`.
224
250
 
225
- Notes:
226
- This method will return a new instance of :class:`Field` instead of
227
- updating the current instance.
251
+ This method will return a new instance of :class:`Field` instead of
252
+ updating the current instance.
228
253
 
229
254
  """
230
255
  new_self = copy.copy(self)
@@ -3,7 +3,6 @@
3
3
 
4
4
  import abc
5
5
  import ipaddress
6
- from sys import prefix
7
6
  from typing import TYPE_CHECKING, Generic, TypeVar, cast
8
7
 
9
8
  from pcapkit.corekit.fields.field import _T, Field, NoValue
@@ -141,9 +141,8 @@ class ConditionalField(_Field[_TC]):
141
141
  Returns:
142
142
  Updated field instance.
143
143
 
144
- Notes:
145
- This method will return a new instance of :class:`ConditionalField`
146
- instead of updating the current instance.
144
+ This method will return a new instance of :class:`ConditionalField`
145
+ instead of updating the current instance.
147
146
 
148
147
  """
149
148
  new_self = copy.copy(self)
@@ -273,7 +272,7 @@ class PayloadField(_Field[_TP]):
273
272
  default: '_TP | NoValueType | bytes' = NoValue,
274
273
  protocol: 'Optional[Type[_TP]]' = None,
275
274
  callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
276
- self._name = '<payload>'
275
+ #self._name = '<payload>'
277
276
  self._default = default # type: ignore[assignment]
278
277
  self._protocol = protocol # type: ignore[assignment]
279
278
  self._callback = callback
@@ -293,9 +292,8 @@ class PayloadField(_Field[_TP]):
293
292
  Returns:
294
293
  Updated field instance.
295
294
 
296
- Notes:
297
- This method will return a new instance of :class:`PayloadField`
298
- instead of updating the current instance.
295
+ This method will return a new instance of :class:`PayloadField`
296
+ instead of updating the current instance.
299
297
 
300
298
  """
301
299
  new_self = copy.copy(self)
@@ -409,7 +407,7 @@ class SwitchField(_Field[_TC]):
409
407
  return self._field
410
408
 
411
409
  def __init__(self, selector: 'Callable[[dict[str, Any]], _Field[_TC]]' = lambda _: NoValueField()) -> 'None': # type: ignore[assignment,return-value]
412
- self._name = '<switch>'
410
+ #self._name = '<switch>'
413
411
  self._field = cast('_Field[_TC]', NoValueField())
414
412
  self._selector = selector
415
413
 
@@ -422,9 +420,8 @@ class SwitchField(_Field[_TC]):
422
420
  Returns:
423
421
  New field instance.
424
422
 
425
- Notes:
426
- This method will return a new instance of :class:`SwitchField`
427
- instead of updating the current instance.
423
+ This method will return a new instance of :class:`SwitchField`
424
+ instead of updating the current instance.
428
425
 
429
426
  """
430
427
  new_self = copy.copy(self)
@@ -527,7 +524,7 @@ class SchemaField(_Field[_TS]):
527
524
  default: '_TS | NoValueType | bytes' = NoValue,
528
525
  packet: 'Optional[dict[str, Any]]' = None,
529
526
  callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
530
- self._name = '<schema>'
527
+ #self._name = '<schema>'
531
528
  self._callback = callback
532
529
 
533
530
  if packet is None:
@@ -557,9 +554,8 @@ class SchemaField(_Field[_TS]):
557
554
  Returns:
558
555
  New field instance.
559
556
 
560
- Notes:
561
- This method will return a new instance of :class:`SchemaField`
562
- instead of updating the current instance.
557
+ This method will return a new instance of :class:`SchemaField`
558
+ instead of updating the current instance.
563
559
 
564
560
  """
565
561
  new_self = copy.copy(self)
@@ -679,7 +675,7 @@ class ForwardMatchField(_Field[_TC]):
679
675
  return self._field
680
676
 
681
677
  def __init__(self, field: '_Field[_TC]') -> 'None':
682
- self._name = '<forward_match>'
678
+ #self._name = '<forward_match>'
683
679
  self._field = field
684
680
 
685
681
  def __call__(self, packet: 'dict[str, Any]') -> 'Self':
@@ -691,9 +687,8 @@ class ForwardMatchField(_Field[_TC]):
691
687
  Returns:
692
688
  Updated field instance.
693
689
 
694
- Notes:
695
- This method will return a new instance of :class:`ConditionalField`
696
- instead of updating the current instance.
690
+ This method will return a new instance of :class:`ConditionalField`
691
+ instead of updating the current instance.
697
692
 
698
693
  """
699
694
  new_self = copy.copy(self)
@@ -92,9 +92,8 @@ class NumberField(Field[int], Generic[_T]):
92
92
  Returns:
93
93
  New instance of :class:`NumberField`.
94
94
 
95
- Notes:
96
- This method will return a new instance of :class:`NumberField` instead of
97
- updating the current instance.
95
+ This method will return a new instance of :class:`NumberField` instead of
96
+ updating the current instance.
98
97
 
99
98
  """
100
99
  new_self = super().__call__(packet)
@@ -56,9 +56,8 @@ class _TextField(Field[_T], Generic[_T]):
56
56
  Returns:
57
57
  New instance of :class:`_TextField`.
58
58
 
59
- Notes:
60
- This method will return a new instance of :class:`_TextField` instead of
61
- updating the current instance.
59
+ This method will return a new instance of :class:`_TextField` instead of
60
+ updating the current instance.
62
61
 
63
62
  """
64
63
  new_self = super().__call__(packet)
@@ -10,6 +10,7 @@ designed to work alike :func:`dataclasses.dataclass` as introduced
10
10
  in :pep:`557`.
11
11
 
12
12
  """
13
+ import abc
13
14
  import collections.abc
14
15
  import enum
15
16
  import itertools
@@ -49,6 +50,11 @@ def info_final(cls: 'ST', *, _finalised: 'bool' = True) -> 'ST':
49
50
  class. It can be useful to reduce runtime generation
50
51
  time as well as caching already generated attributes.
51
52
 
53
+ Notes:
54
+ The decorator should only be used on the *final*
55
+ class, otherwise, any subclasses derived from a
56
+ finalised info class will not be re-finalised.
57
+
52
58
  Args:
53
59
  cls: Info class.
54
60
  _finalised: Whether to make the info class as finalised.
@@ -56,11 +62,6 @@ def info_final(cls: 'ST', *, _finalised: 'bool' = True) -> 'ST':
56
62
  Returns:
57
63
  Finalised info class.
58
64
 
59
- Notes:
60
- The decorator should only be used on the *final*
61
- class, otherwise, any subclasses derived from a
62
- finalised info class will not be re-finalised.
63
-
64
65
  :meta decorator:
65
66
  """
66
67
  if cls.__finalised__ == FinalisedState.FINAL:
@@ -140,7 +141,59 @@ def info_final(cls: 'ST', *, _finalised: 'bool' = True) -> 'ST':
140
141
  return final(cls)
141
142
 
142
143
 
143
- class Info(Mapping[str, VT], Generic[VT]):
144
+ class InfoMeta(abc.ABCMeta):
145
+ """Meta class to add dynamic support to :class:`Info`.
146
+
147
+ This meta class is used to generate necessary attributes for the
148
+ :class:`Info` class. It can be useful to reduce runtime generation
149
+ cost as well as caching already generated attributes.
150
+
151
+ * :attr:`Info.__additional__` and :attr:`Info.__excluded__` are
152
+ lists of additional and excluded field names, which are used to
153
+ determine certain names to be included or excluded from the field
154
+ dictionary. They will be automatically populated from the class
155
+ attributes of the :class:`Info` class and its base classes.
156
+
157
+ .. note::
158
+
159
+ This is implemented thru the :meth:`__new__` method, which will
160
+ inherit the additional and excluded field names from the base
161
+ classes, as well as populating the additional and excluded field
162
+ from the subclass attributes.
163
+
164
+ .. code-block:: python
165
+
166
+ class A(Info):
167
+ __additional__ = ['a', 'b']
168
+
169
+ class B(A):
170
+ __additional__ = ['c', 'd']
171
+
172
+ class C(B):
173
+ __additional__ = ['e', 'f']
174
+
175
+ print(A.__additional__) # ['a', 'b']
176
+ print(B.__additional__) # ['a', 'b', 'c', 'd']
177
+ print(C.__additional__) # ['a', 'b', 'c', 'd', 'e', 'f']
178
+
179
+ """
180
+
181
+ def __new__(cls, name: 'str', bases: 'tuple[type, ...]', attrs: 'dict[str, Any]', **kwargs: 'Any') -> 'Type[Info]':
182
+ if '__additional__' not in attrs:
183
+ attrs['__additional__'] = []
184
+ if '__excluded__' not in attrs:
185
+ attrs['__excluded__'] = []
186
+
187
+ for base in bases:
188
+ if hasattr(base, '__additional__'):
189
+ attrs['__additional__'].extend(
190
+ name for name in base.__additional__ if name not in attrs['__additional__'])
191
+ if hasattr(base, '__excluded__'):
192
+ attrs['__excluded__'].extend(name for name in base.__excluded__ if name not in attrs['__excluded__'])
193
+ return super().__new__(cls, name, bases, attrs, **kwargs) # type: ignore[return-value]
194
+
195
+
196
+ class Info(Mapping[str, VT], Generic[VT], metaclass=InfoMeta):
144
197
  """Turn dictionaries into :obj:`object` like instances.
145
198
 
146
199
  * :class:`Info` objects inherit from :obj:`dict` type
@@ -26,7 +26,14 @@ __all__ = ['ProtoChain']
26
26
 
27
27
 
28
28
  class ProtoChain(collections.abc.Sequence):
29
- """Protocols chain."""
29
+ """Protocols chain.
30
+
31
+ Args:
32
+ proto: New protocol class on the top stack.
33
+ alias: New protocol alias on the top stack.
34
+ basis: Original protocol chain as base stacks.
35
+
36
+ """
30
37
 
31
38
  #: Internal data storage for protocol chain.
32
39
  __data__: 'tuple[tuple[str, Type[Protocol]], ...]'