Skip to content

Commit 588390f

Browse files
authored
move creation of __public_fields__ out of __init__; make it a class attribute (#612)
1 parent 09ac218 commit 588390f

File tree

1 file changed

+37
-30
lines changed

1 file changed

+37
-30
lines changed

dpkt/dpkt.py

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ def delete_func(self):
107107
# define as needed in the child protocol classes
108108
#t.__pprint_funcs__ = {} - disabled here to keep the base class lightweight
109109

110+
# placeholder for __public_fields__, a class attribute used in __repr__ and pprint()
111+
t.__public_fields__ = None
112+
110113
return t
111114

112115

@@ -138,7 +141,6 @@ class Packet(_MetaPacket("Temp", (object,), {})):
138141
>>> Foo('hello, world!')
139142
Foo(baz=' wor', foo=1751477356L, bar=28460, data='ld!')
140143
"""
141-
142144
def __init__(self, *args, **kwargs):
143145
"""Packet constructor with ([buf], [field=val,...]) prototype.
144146
@@ -169,9 +171,31 @@ def __init__(self, *args, **kwargs):
169171
if hasattr(self, '__hdr_fmt__'):
170172
self._pack_hdr = partial(struct.pack, self.__hdr_fmt__)
171173

172-
# construct __public_fields__ to be used inside __repr__ and pprint
173-
# once auto-formed here in __init__, the list can be customized in
174-
# child classes to include or remove fields to display, as needed
174+
def __len__(self):
175+
return self.__hdr_len__ + len(self.data)
176+
177+
# legacy
178+
def __iter__(self):
179+
return iter((fld, getattr(self, fld)) for fld in self.__class__.__hdr_fields__)
180+
181+
def __getitem__(self, kls):
182+
"""Return the 1st occurence of the underlying <kls> data layer, raise KeyError otherwise."""
183+
dd = self.data
184+
while isinstance(dd, Packet):
185+
if dd.__class__ == kls:
186+
return dd
187+
dd = dd.data
188+
raise KeyError(kls)
189+
190+
def __contains__(self, kls):
191+
"""Return True is the given <kls> data layer is present in the stack."""
192+
try:
193+
return bool(self.__getitem__(kls))
194+
except KeyError:
195+
return False
196+
197+
def _create_public_fields(self):
198+
"""Construct __public_fields__ to be used inside __repr__ and pprint"""
175199
l_ = []
176200
for field_name, _, _ in getattr(self, '__hdr__', []):
177201
# public fields defined in __hdr__; "public" means not starting with an underscore
@@ -202,32 +226,12 @@ def __init__(self, *args, **kwargs):
202226

203227
# check for duplicates, there shouldn't be any
204228
assert len(l_) == len(set(l_))
205-
self.__public_fields__ = l_
206-
207-
def __len__(self):
208-
return self.__hdr_len__ + len(self.data)
209-
210-
# legacy
211-
def __iter__(self):
212-
return iter((fld, getattr(self, fld)) for fld in self.__class__.__hdr_fields__)
213-
214-
def __getitem__(self, kls):
215-
"""Return the 1st occurence of the underlying <kls> data layer, raise KeyError otherwise."""
216-
dd = self.data
217-
while isinstance(dd, Packet):
218-
if dd.__class__ == kls:
219-
return dd
220-
dd = dd.data
221-
raise KeyError(kls)
222-
223-
def __contains__(self, kls):
224-
"""Return True is the given <kls> data layer is present in the stack."""
225-
try:
226-
return bool(self.__getitem__(kls))
227-
except KeyError:
228-
return False
229+
self.__class__.__public_fields__ = l_ # store it in the class attribute
229230

230231
def __repr__(self):
232+
if self.__public_fields__ is None:
233+
self._create_public_fields()
234+
231235
# Collect and display protocol fields in order:
232236
# 1. public fields defined in __hdr__, unless their value is default
233237
# 2. properties derived from _private fields defined in __hdr__ and __bit_fields__
@@ -236,7 +240,7 @@ def __repr__(self):
236240
l_ = []
237241

238242
# (1) and (2) are done via __public_fields__; just filter out defaults here
239-
for field_name in getattr(self, '__public_fields__', []):
243+
for field_name in self.__public_fields__:
240244
field_value = getattr(self, field_name)
241245

242246
if (hasattr(self, '__hdr_defaults__') and
@@ -264,6 +268,9 @@ def __repr__(self):
264268

265269
def pprint(self, indent=1):
266270
"""Human friendly pretty-print."""
271+
if self.__public_fields__ is None:
272+
self._create_public_fields()
273+
267274
l_ = []
268275

269276
def add_field(fn, fv):
@@ -273,7 +280,7 @@ def add_field(fn, fv):
273280
except (AttributeError, KeyError):
274281
l_.append('%s=%r,' % (fn, fv))
275282

276-
for field_name in getattr(self, '__public_fields__', []):
283+
for field_name in self.__public_fields__:
277284
add_field(field_name, getattr(self, field_name))
278285

279286
for attr_name, attr_value in iteritems(self.__dict__):

0 commit comments

Comments
 (0)