This post is actually an edit of an old post because the previous one wasn't clear at all on my issue.
I think I have issues regarding what's really going on when you create instances of classes that heritates from another class and share a same attribute.
I have a piece of code, which uses the library Packet from scapy.packets. Its prupose is to create a header, a data layer, combine those two to form a packet.
I decided to create two classes Header and Layer which both heritate from Packet and therefor share the class attribute fields_desc. In these two classes I added two classmethods in order to add some fields to my soon-to-be packet. I then create an instance of my header, an instance of my layer and combine these two packets to form the final packet :
class Init:
class Header(Packet):
name = "RESM_header"
fields_desc = []
@classmethod
def add_IntField(cls, name, value):
cls.fields_desc.append(IntField(name, value))
@classmethod
def reset(cls):
"""
Allows for the fields_desc to be set to []
"""
cls.fields_desc=[]
class Layer(Packet):
name = "DATA"
fields_desc = []
@classmethod
def add_IntField(cls, name, value):
cls.fields_desc.append(IntField(name, value))
@classmethod
def reset(cls):
"""
Allows for the fields_desc to be set to []
"""
cls.fields_desc = []
If I then want to create a header with the field "id" I will use :
if __name__ == '__main__':
Init.Header.add_IntField("id",4) # adds the requested field with its value
a = Init.Header() # creates the packet with the fields_desc already filled
If I show the packet I have the result :
a.show()
###[ RESM_header ]###
id = 4
However, in my overall project, I have to create several different headers. I would like for instance to reset the fields_desc of my header with python a.reset()
and then add a new field with python Init.Header.add_IntField("id",6)
with a new value.
However the value of my id is still the previous value. The following code returns the same packet twice :
if __name__ == '__main__':
Init.Header.add_IntField("id",4)
a = Init.Header()
a.show()
a.reset()
Init.Header.add_IntField("id",5)
a = Init.Header()
a.show()
a.reset()
Even weirder, if i decide to create another field different than the previous one, the code goes brrrr with several errors :
if __name__ == '__main__':
Init.Header.add_IntField("id",4)
a = Init.Header()
a.show()
a.reset()
Init.Header.add_IntField("another_field",5) # try to create another field
a = Init.Header()
a.show()
a.reset()
returns the error :
Traceback (most recent call last):
File "F:/IVS_NG/Tests/DebugTest.py", line 46, in <module>
a.show()
File "D:\Users\T0267246-A\AppData\Roaming\Python\Python37\site-packages\scapy\packet.py", line 1464, in show
return self._show_or_dump(dump, indent, lvl, label_lvl)
File "D:\Users\T0267246-A\AppData\Roaming\Python\Python37\site-packages\scapy\packet.py", line 1414, in _show_or_dump
fvalue = self.getfieldval(f.name)
File "D:\Users\T0267246-A\AppData\Roaming\Python\Python37\site-packages\scapy\packet.py", line 411, in getfieldval
return self.payload.getfieldval(attr)
File "D:\Users\T0267246-A\AppData\Roaming\Python\Python37\site-packages\scapy\packet.py", line 1824, in getfieldval
raise AttributeError(attr)
AttributeError: another_field
If anyone has an idea of what's going on I'd be very grateful ! Cheers
I'm gonna post this as an answer because it wouldn't fit in the comments. I'm no expert on scapy, so I don't know if this'll do what you need, but after having skimmed the docs it appears to me that it isn't designed to dynamically change the fields like you're trying to do. Instead, you should define all the fields up front, and then you can set the values per instance. For example, your Header
class might look like this:
class Header(Packet):
name = "RESM_header"
fields_desc = [ IntField("id", 0) ] # define a field called "id" with default 0
And that's it, really. Now you can create a Header
instance with any id you want like this:
header = Header(id = 12345) # pass the desired id to the constructor here
header.show()
# ###[ RESM_header ]###
# id = 12345
If you need Header
to have another field, just add it to the fields_desc
list statically:
class Header(Packet):
name = "RESM_header"
fields_desc = [ IntField("id", 0),
IntField("another_field", 0) ]
And create your instance like before:
header = Header(id = 12345, another_field = 69)
header.show()
# ###[ RESM_header ]###
# id = 12345
# another_field= 69