Skip to content

Commit 10b0860

Browse files
committed
Pickle - support extra slots
1 parent b9f54f2 commit 10b0860

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

scapy/packet.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def _rebuild_pkt(
8484
fields, # type: Dict[str, Any]
8585
payload, # type: Optional[Packet]
8686
metadata, # type: Dict[str, Any]
87+
extra_slots=None, # type: Dict[str, Any]
8788
):
8889
# type: (...) -> Packet
8990
"""Helper for unpickling Packet instances via field values."""
@@ -98,6 +99,9 @@ def _rebuild_pkt(
9899
pkt.sniffed_on = metadata['sniffed_on']
99100
pkt.wirelen = metadata['wirelen']
100101
pkt.comments = metadata['comments']
102+
# Restore any extra __slots__ defined by subclasses
103+
for attr, value in extra_slots.items():
104+
setattr(pkt, attr, value)
101105
return pkt
102106

103107

@@ -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 (
283292
_rebuild_pkt,
284-
(self.__class__, fields, payload, metadata),
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)