Skip to content

Commit 048733b

Browse files
guedougg-gvaladon
authored andcommitted
Pickle - support extra slots
1 parent b9f54f2 commit 048733b

2 files changed

Lines changed: 64 additions & 24 deletions

File tree

scapy/packet.py

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -79,28 +79,6 @@
7979
_T = TypeVar("_T", Dict[str, Any], Optional[Dict[str, Any]])
8080

8181

82-
def _rebuild_pkt(
83-
cls, # type: Type[Packet]
84-
fields, # type: Dict[str, Any]
85-
payload, # type: Optional[Packet]
86-
metadata, # type: Dict[str, Any]
87-
):
88-
# type: (...) -> Packet
89-
"""Helper for unpickling Packet instances via field values."""
90-
# Create the instance using the field values
91-
pkt = cls(**fields)
92-
if payload is not None:
93-
pkt.add_payload(payload)
94-
# Restore metadata
95-
pkt.time = metadata['time']
96-
pkt.sent_time = metadata['sent_time']
97-
pkt.direction = metadata['direction']
98-
pkt.sniffed_on = metadata['sniffed_on']
99-
pkt.wirelen = metadata['wirelen']
100-
pkt.comments = metadata['comments']
101-
return pkt
102-
103-
10482
class Packet(
10583
BasePacket,
10684
_CanvasDumpExtended,
@@ -256,6 +234,32 @@ def comment(self, value):
256234
else:
257235
self.comments = None
258236

237+
@classmethod
238+
def _rebuild_pkt(
239+
cls, # type: Type[Packet]
240+
fields, # type: Dict[str, Any]
241+
payload, # type: Optional[Packet]
242+
metadata, # type: Dict[str, Any]
243+
extra_slots={}, # type: Dict[str, Any]
244+
):
245+
# type: (...) -> Packet
246+
"""Helper for unpickling Packet instances via field values."""
247+
# Create the instance using the field values
248+
pkt = cls(**fields)
249+
if payload is not None:
250+
pkt.add_payload(payload)
251+
# Restore metadata
252+
pkt.time = metadata['time']
253+
pkt.sent_time = metadata['sent_time']
254+
pkt.direction = metadata['direction']
255+
pkt.sniffed_on = metadata['sniffed_on']
256+
pkt.wirelen = metadata['wirelen']
257+
pkt.comments = metadata['comments']
258+
# Restore any extra __slots__ defined by subclasses
259+
for attr, value in extra_slots.items():
260+
setattr(pkt, attr, value)
261+
return pkt
262+
259263
def __reduce__(self):
260264
# type: () -> Tuple[Any, ...]
261265
"""Used by pickling methods.
@@ -279,9 +283,14 @@ def __reduce__(self):
279283
'wirelen': self.wirelen,
280284
'comments': self.comments,
281285
}
286+
# Collect any extra __slots__ defined by subclasses
287+
extra_slots = {}
288+
for attr in type(self).__all_slots__ - set(Packet.__slots__):
289+
if hasattr(self, attr):
290+
extra_slots[attr] = getattr(self, attr)
282291
return (
283-
_rebuild_pkt,
284-
(self.__class__, fields, payload, metadata),
292+
self._rebuild_pkt,
293+
(self.__class__, fields, payload, metadata, extra_slots),
285294
)
286295

287296
def __deepcopy__(self,

test/regression.uts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,37 @@ p2 = pickle.loads(pickle.dumps(p))
653653
assert p2.src == '10.0.0.1'
654654
assert raw(p2) == raw(p)
655655

656+
= Pickle preserves custom __slots__ from subclasses
657+
658+
import pickle
659+
import scapy.packet as _pkt_mod
660+
661+
class _PickleTestPacket(Packet):
662+
__slots__ = ["custom_id", "custom_tag"]
663+
name = "PickleTestPacket"
664+
fields_desc = [ByteField("val", 0)]
665+
666+
# Make the class discoverable by pickle
667+
_pkt_mod._PickleTestPacket = _PickleTestPacket
668+
_PickleTestPacket.__module__ = 'scapy.packet'
669+
670+
p = _PickleTestPacket(val=42)
671+
p.custom_id = 0x123
672+
p.custom_tag = "hello"
673+
p2 = pickle.loads(pickle.dumps(p))
674+
assert p2.val == 42
675+
assert p2.custom_id == 0x123
676+
assert p2.custom_tag == "hello"
677+
678+
# Slots not explicitly set are not serialized
679+
p3 = _PickleTestPacket(val=7)
680+
assert not hasattr(p3, 'custom_id')
681+
p4 = pickle.loads(pickle.dumps(p3))
682+
assert p4.val == 7
683+
assert not hasattr(p4, 'custom_id')
684+
685+
del _pkt_mod._PickleTestPacket
686+
656687
= Usage test
657688

658689
from scapy.main import _usage

0 commit comments

Comments
 (0)