Skip to content

Commit deee6b1

Browse files
committed
revised TraceFlow metaclass
* added a TraceFlowMeta for better processing * use TraceFlowBase for internally defined engines * added TraceFlow wrapper for external customised engines with auto registration
1 parent fefab8d commit deee6b1

File tree

3 files changed

+125
-43
lines changed

3 files changed

+125
-43
lines changed

docs/source/pcapkit/foundation/traceflow/traceflow.rst

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,40 @@ Base Class
88
which is an abstract base class for all flow tracing classes.
99

1010
.. autoclass:: pcapkit.foundation.traceflow.traceflow.TraceFlow
11-
:no-members:
11+
:members:
1212
:show-inheritance:
1313

14-
.. autoproperty:: name
15-
.. autoproperty:: protocol
16-
.. autoproperty:: index
14+
.. .. autoproperty:: name
15+
.. .. autoproperty:: protocol
16+
.. .. autoproperty:: index
1717
18-
.. automethod:: register_dumper
19-
.. automethod:: register_callback
20-
.. automethod:: make_fout
18+
.. .. automethod:: register_dumper
19+
.. .. automethod:: register_callback
20+
.. .. automethod:: make_fout
2121
22-
.. automethod:: dump
23-
.. automethod:: trace
24-
.. automethod:: submit
22+
.. .. automethod:: dump
23+
.. .. automethod:: trace
24+
.. .. automethod:: submit
2525
26-
.. autoattribute:: __output__
27-
:no-value:
28-
.. autoattribute:: __callback_fn__
29-
:no-value:
26+
.. .. autoattribute:: __output__
27+
.. :no-value:
28+
.. .. autoattribute:: __callback_fn__
29+
.. :no-value:
3030
31-
.. autoattribute:: _buffer
32-
:no-value:
33-
.. autoattribute:: _stream
34-
:no-value:
31+
.. .. autoattribute:: _buffer
32+
.. :no-value:
33+
.. .. autoattribute:: _stream
34+
.. :no-value:
3535
36-
.. automethod:: __call__
36+
.. .. automethod:: __call__
37+
38+
Internal Definitions
39+
--------------------
40+
41+
.. autoclass:: pcapkit.foundation.traceflow.traceflow.TraceFlowBase
42+
:members:
43+
:show-inheritance:
44+
45+
.. autoclass:: pcapkit.foundation.traceflow.traceflow.TraceFlowMeta
46+
:members:
47+
:show-inheritance:

pcapkit/foundation/traceflow/tcp.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@
1212
from typing import TYPE_CHECKING, Generic, overload
1313

1414
from pcapkit.foundation.traceflow.data.tcp import Buffer, BufferID, Index, IPAddress, Packet
15-
from pcapkit.foundation.traceflow.traceflow import TraceFlow
15+
from pcapkit.foundation.traceflow.traceflow import TraceFlowBase as TraceFlow
1616
from pcapkit.protocols.transport.tcp import TCP as TCP_Protocol
1717

1818
__all__ = ['TCP']
1919

2020
if TYPE_CHECKING:
21-
from typing import Type
22-
2321
from dictdumper.dumper import Dumper
2422
from typing_extensions import Literal
2523

@@ -38,18 +36,13 @@ class TCP(TraceFlow[BufferID, Buffer, Index, Packet[IPAddress]], Generic[IPAddre
3836
"""
3937

4038
##########################################################################
41-
# Methods.
39+
# Defaults.
4240
##########################################################################
4341

44-
@property
45-
def name(self) -> 'Literal["Transmission Control Protocol"]':
46-
"""Protocol of current packet."""
47-
return 'Transmission Control Protocol'
48-
49-
@property
50-
def protocol(self) -> 'Type[TCP_Protocol]':
51-
"""Protocol of current reassembly object."""
52-
return TCP_Protocol
42+
#: Protocol name of current reassembly object.
43+
__protocol_name__ = 'TCP'
44+
#: Protocol of current reassembly object.
45+
__protocol_type__ = TCP_Protocol
5346

5447
##########################################################################
5548
# Methods.

pcapkit/foundation/traceflow/traceflow.py

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
from pcapkit.corekit.module import ModuleDescriptor
2222
from pcapkit.dumpkit.common import make_dumper
23+
from pcapkit.protocols import __proto__ as protocol_registry
24+
from pcapkit.protocols.misc.raw import Raw
2325
from pcapkit.utilities.exceptions import FileExists, RegistryError, stacklevel
2426
from pcapkit.utilities.warnings import FileWarning, FormatWarning, RegistryWarning, warn
2527

@@ -41,7 +43,36 @@
4143
Packet = TypeVar('Packet', bound='Info')
4244

4345

44-
class TraceFlow(Generic[BufferID, Buffer, Index, Packet], metaclass=abc.ABCMeta):
46+
class TraceFlowMeta(abc.ABCMeta):
47+
"""Meta class to add dynamic support to :class:`TraceFlow`.
48+
49+
This meta class is used to generate necessary attributes for the
50+
:class:`TraceFlow` class. It can be useful to reduce unnecessary
51+
registry calls and simplify the customisation process.
52+
53+
"""
54+
if TYPE_CHECKING:
55+
#: Protocol name of current reassembly object.
56+
__protocol_name__: 'str'
57+
#: Protocol of current reassembly object.
58+
__protocol_type__: 'Type[Protocol]'
59+
60+
@property
61+
def name(cls) -> 'str':
62+
"""Protocol name of current reassembly object."""
63+
if hasattr(cls, '__protocol_name__'):
64+
return cls.__protocol_name__
65+
return cls.__name__
66+
67+
@property
68+
def protocol(cls) -> 'Type[Protocol]':
69+
"""Protocol of current reassembly object."""
70+
if hasattr(cls, '__protocol_type__'):
71+
return cls.__protocol_type__
72+
return protocol_registry.get(cls.name.upper(), Raw)
73+
74+
75+
class TraceFlowBase(Generic[BufferID, Buffer, Index, Packet], metaclass=TraceFlowMeta):
4576
"""Base flow tracing class.
4677
4778
Arguments:
@@ -52,7 +83,16 @@ class TraceFlow(Generic[BufferID, Buffer, Index, Packet], metaclass=abc.ABCMeta)
5283
*args: Arbitrary positional arguments.
5384
**kwargs: Arbitrary keyword arguments.
5485
86+
Note:
87+
This class is for internal use only. For customisation, please use
88+
:class:`TraceFlow` instead.
89+
5590
"""
91+
if TYPE_CHECKING:
92+
#: Protocol name of current reassembly object.
93+
__protocol_name__: 'str'
94+
#: Protocol of current reassembly object.
95+
__protocol_type__: 'Type[Protocol]'
5696

5797
# Internal data storage for cached properties.
5898
__cached__: 'dict[str, Any]'
@@ -86,16 +126,6 @@ class TraceFlow(Generic[BufferID, Buffer, Index, Packet], metaclass=abc.ABCMeta)
86126
# Properties.
87127
##########################################################################
88128

89-
@property
90-
@abc.abstractmethod
91-
def name(self) -> 'str':
92-
"""Protocol name of current reassembly object."""
93-
94-
@property
95-
@abc.abstractmethod
96-
def protocol(self) -> 'Type[Protocol]':
97-
"""Protocol of current reassembly object."""
98-
99129
@property
100130
def index(self) -> 'tuple[Index, ...]':
101131
"""Index table for traced flow."""
@@ -278,3 +308,51 @@ def __call__(self, packet: 'Packet') -> 'None':
278308
"""
279309
# trace frame record
280310
self.dump(packet)
311+
312+
313+
class TraceFlow(TraceFlowBase[BufferID, Buffer, Index, Packet], Generic[BufferID, Buffer, Index, Packet]):
314+
"""Base flow tracing class.
315+
316+
Example:
317+
318+
Use keyword argument ``protocol`` to specify the protocol
319+
name at class definition:
320+
321+
.. code-block:: python
322+
323+
class MyProtocol(TraceFlow, protocol='my_protocol'):
324+
...
325+
326+
Arguments:
327+
fout: output path
328+
format: output format
329+
byteorder: output file byte order
330+
nanosecond: output nanosecond-resolution file flag
331+
*args: Arbitrary positional arguments.
332+
**kwargs: Arbitrary keyword arguments.
333+
334+
"""
335+
336+
def __init_subclass__(cls, /, protocol: 'Optional[str]' = None, *args: 'Any', **kwargs: 'Any') -> 'None':
337+
"""Initialise subclass.
338+
339+
This method is to be used for registering the engine class to
340+
:class:`~pcapkit.foundation.extraction.Extractor` class.
341+
342+
Args:
343+
name: Protocol name, default to class name.
344+
*args: Arbitrary positional arguments.
345+
**kwargs: Arbitrary keyword arguments.
346+
347+
See Also:
348+
For more details, please refer to
349+
:meth:`~pcapkit.foundation.extraction.Extractor.register_traceflow`.
350+
351+
"""
352+
if protocol is None:
353+
protocol = cls.name
354+
355+
from pcapkit.foundation.extraction import Extractor
356+
Extractor.register_traceflow(protocol.lower(), cls)
357+
358+
return super().__init_subclass__()

0 commit comments

Comments
 (0)