mirror of https://gerrit.osmocom.org/pysim
utils.py: type annotations for DataObject related methods
Change-Id: I291a429e9fe9f1a3fd95dcba3020b0e982154c97
This commit is contained in:
parent
b060833e9a
commit
5036877147
|
@ -1170,7 +1170,7 @@ class DataObject(abc.ABC):
|
||||||
simply has any number of different TLVs that may occur in any order at any point, ISO 7816
|
simply has any number of different TLVs that may occur in any order at any point, ISO 7816
|
||||||
has the habit of specifying TLV data but with very spcific ordering, or specific choices of
|
has the habit of specifying TLV data but with very spcific ordering, or specific choices of
|
||||||
tags at specific points in a stream. This class tries to represent this."""
|
tags at specific points in a stream. This class tries to represent this."""
|
||||||
def __init__(self, name, desc = None, tag = None):
|
def __init__(self, name:str, desc:str = None, tag:int = None):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
name: A brief, all-lowercase, underscore separated string identifier
|
name: A brief, all-lowercase, underscore separated string identifier
|
||||||
|
@ -1186,10 +1186,10 @@ class DataObject(abc.ABC):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
return '%s(%s)' % (self.__class__, self.name)
|
return '%s(%s)' % (self.__class__, self.name)
|
||||||
|
|
||||||
def __or__(self, other):
|
def __or__(self, other) -> 'DataObjectChoice':
|
||||||
"""OR-ing DataObjects together renders a DataObjectChoice."""
|
"""OR-ing DataObjects together renders a DataObjectChoice."""
|
||||||
if isinstance(other, DataObject):
|
if isinstance(other, DataObject):
|
||||||
# DataObject | DataObject = DataObjectChoice
|
# DataObject | DataObject = DataObjectChoice
|
||||||
|
@ -1197,17 +1197,19 @@ class DataObject(abc.ABC):
|
||||||
else:
|
else:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other) -> 'DataObjectCollection':
|
||||||
"""ADD-ing DataObjects together renders a DataObjectCollection."""
|
"""ADD-ing DataObjects together renders a DataObjectCollection."""
|
||||||
if isinstance(other, DataObject):
|
if isinstance(other, DataObject):
|
||||||
# DataObject + DataObject = DataObjectCollectin
|
# DataObject + DataObject = DataObjectCollectin
|
||||||
return DataObjectCollection(None, members=[self, other])
|
return DataObjectCollection(None, members=[self, other])
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
def _compute_tag(self):
|
def _compute_tag(self) -> int:
|
||||||
"""Compute the tag (sometimes the tag encodes part of the value)."""
|
"""Compute the tag (sometimes the tag encodes part of the value)."""
|
||||||
return self.tag
|
return self.tag
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self) -> dict:
|
||||||
"""Return a dict in form "name: decoded_value" """
|
"""Return a dict in form "name: decoded_value" """
|
||||||
return {self.name: self.decoded}
|
return {self.name: self.decoded}
|
||||||
|
|
||||||
|
@ -1219,13 +1221,13 @@ class DataObject(abc.ABC):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def to_bytes(self):
|
def to_bytes(self) -> bytes:
|
||||||
"""Encode the internal state of this instance into the TLV value part.
|
"""Encode the internal state of this instance into the TLV value part.
|
||||||
Returns:
|
Returns:
|
||||||
binary bytes encoding the internal state
|
binary bytes encoding the internal state
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def from_tlv(self, do:bytes):
|
def from_tlv(self, do:bytes) -> bytes:
|
||||||
"""Parse binary TLV representation into internal state. The resulting decoded
|
"""Parse binary TLV representation into internal state. The resulting decoded
|
||||||
representation is _not_ returned, but just internalized in the object instance!
|
representation is _not_ returned, but just internalized in the object instance!
|
||||||
Args:
|
Args:
|
||||||
|
@ -1241,7 +1243,7 @@ class DataObject(abc.ABC):
|
||||||
# return remaining bytes
|
# return remaining bytes
|
||||||
return do[2+length:]
|
return do[2+length:]
|
||||||
|
|
||||||
def to_tlv(self):
|
def to_tlv(self) -> bytes:
|
||||||
"""Encode internal representation to binary TLV.
|
"""Encode internal representation to binary TLV.
|
||||||
Returns:
|
Returns:
|
||||||
bytes encoded in TLV format.
|
bytes encoded in TLV format.
|
||||||
|
@ -1250,7 +1252,7 @@ class DataObject(abc.ABC):
|
||||||
return bytes(self._compute_tag()) + bytes(len(val)) + val
|
return bytes(self._compute_tag()) + bytes(len(val)) + val
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def decode(self, binary:bytes):
|
def decode(self, binary:bytes) -> Tuple[dict, bytes]:
|
||||||
"""Decode a single DOs from the input data.
|
"""Decode a single DOs from the input data.
|
||||||
Args:
|
Args:
|
||||||
binary : binary bytes of encoded data
|
binary : binary bytes of encoded data
|
||||||
|
@ -1265,12 +1267,12 @@ class DataObject(abc.ABC):
|
||||||
return (self.to_dict(), remainder)
|
return (self.to_dict(), remainder)
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def encode(self):
|
def encode(self) -> bytes:
|
||||||
return self.to_tlv()
|
return self.to_tlv()
|
||||||
|
|
||||||
class TL0_DataObject(DataObject):
|
class TL0_DataObject(DataObject):
|
||||||
"""Data Object that has Tag, Len=0 and no Value part."""
|
"""Data Object that has Tag, Len=0 and no Value part."""
|
||||||
def __init__(self, name, desc, tag, val=None):
|
def __init__(self, name:str, desc:str, tag:int, val=None):
|
||||||
super().__init__(name, desc, tag)
|
super().__init__(name, desc, tag)
|
||||||
self.val = val
|
self.val = val
|
||||||
|
|
||||||
|
@ -1279,7 +1281,7 @@ class TL0_DataObject(DataObject):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
self.decoded = self.val
|
self.decoded = self.val
|
||||||
|
|
||||||
def to_bytes(self):
|
def to_bytes(self) -> bytes:
|
||||||
return b''
|
return b''
|
||||||
|
|
||||||
|
|
||||||
|
@ -1287,7 +1289,7 @@ class DataObjectCollection:
|
||||||
"""A DataObjectCollection consits of multiple Data Objects identified by their tags.
|
"""A DataObjectCollection consits of multiple Data Objects identified by their tags.
|
||||||
A given encoded DO may contain any of them in any order, and may contain multiple instances
|
A given encoded DO may contain any of them in any order, and may contain multiple instances
|
||||||
of each DO."""
|
of each DO."""
|
||||||
def __init__(self, name, desc = None, members=None):
|
def __init__(self, name:str, desc:str = None, members=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.desc = desc
|
self.desc = desc
|
||||||
self.members = members or []
|
self.members = members or []
|
||||||
|
@ -1296,15 +1298,15 @@ class DataObjectCollection:
|
||||||
self.members_by_tag = { m.tag:m for m in members }
|
self.members_by_tag = { m.tag:m for m in members }
|
||||||
self.members_by_name = { m.name:m for m in members }
|
self.members_by_name = { m.name:m for m in members }
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
member_strs = [str(x) for x in self.members]
|
member_strs = [str(x) for x in self.members]
|
||||||
return '%s(%s)' % (self.name, ','.join(member_strs))
|
return '%s(%s)' % (self.name, ','.join(member_strs))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
member_strs = [repr(x) for x in self.members]
|
member_strs = [repr(x) for x in self.members]
|
||||||
return '%s(%s)' % (self.__class__, ','.join(member_strs))
|
return '%s(%s)' % (self.__class__, ','.join(member_strs))
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other) -> 'DataObjectCollection':
|
||||||
"""Extending DataCollections with other DataCollections or DataObjects."""
|
"""Extending DataCollections with other DataCollections or DataObjects."""
|
||||||
if isinstance(other, DataObjectCollection):
|
if isinstance(other, DataObjectCollection):
|
||||||
# adding one collection to another
|
# adding one collection to another
|
||||||
|
@ -1317,7 +1319,7 @@ class DataObjectCollection:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def decode(self, binary:bytes):
|
def decode(self, binary:bytes) -> Tuple[List, bytes]:
|
||||||
"""Decode any number of DOs from the collection until the end of the input data,
|
"""Decode any number of DOs from the collection until the end of the input data,
|
||||||
or uninitialized memory (0xFF) is found.
|
or uninitialized memory (0xFF) is found.
|
||||||
Args:
|
Args:
|
||||||
|
@ -1343,7 +1345,7 @@ class DataObjectCollection:
|
||||||
return (res, remainder)
|
return (res, remainder)
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def encode(self, decoded):
|
def encode(self, decoded) -> bytes:
|
||||||
res = bytearray()
|
res = bytearray()
|
||||||
for i in decoded:
|
for i in decoded:
|
||||||
obj = self.members_by_name(i[0])
|
obj = self.members_by_name(i[0])
|
||||||
|
@ -1358,7 +1360,7 @@ class DataObjectChoice(DataObjectCollection):
|
||||||
"""We overload the add operator here to avoid inheriting it from DataObjecCollection."""
|
"""We overload the add operator here to avoid inheriting it from DataObjecCollection."""
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
def __or__(self, other):
|
def __or__(self, other) -> 'DataObjectChoice':
|
||||||
"""OR-ing a Choice to another choice extends the choice, as does OR-ing a DataObject."""
|
"""OR-ing a Choice to another choice extends the choice, as does OR-ing a DataObject."""
|
||||||
if isinstance(other, DataObjectChoice):
|
if isinstance(other, DataObjectChoice):
|
||||||
# adding one collection to another
|
# adding one collection to another
|
||||||
|
@ -1371,7 +1373,7 @@ class DataObjectChoice(DataObjectCollection):
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def decode(self, binary:bytes):
|
def decode(self, binary:bytes) -> Tuple[dict, bytes]:
|
||||||
"""Decode a single DOs from the choice based on the tag.
|
"""Decode a single DOs from the choice based on the tag.
|
||||||
Args:
|
Args:
|
||||||
binary : binary bytes of encoded data
|
binary : binary bytes of encoded data
|
||||||
|
@ -1389,7 +1391,7 @@ class DataObjectChoice(DataObjectCollection):
|
||||||
return (obj.to_dict(), remainder)
|
return (obj.to_dict(), remainder)
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def encode(self, decoded):
|
def encode(self, decoded) -> bytes:
|
||||||
obj = self.members_by_name(decoded[0])
|
obj = self.members_by_name(decoded[0])
|
||||||
return obj.to_tlv()
|
return obj.to_tlv()
|
||||||
|
|
||||||
|
@ -1398,20 +1400,20 @@ class DataObjectSequence:
|
||||||
ordered sequence of DOs or choices of DOs that have to appear as per the specification.
|
ordered sequence of DOs or choices of DOs that have to appear as per the specification.
|
||||||
By wrapping them into this formal DataObjectSequence, we can offer convenience methods
|
By wrapping them into this formal DataObjectSequence, we can offer convenience methods
|
||||||
for encoding or decoding an entire sequence."""
|
for encoding or decoding an entire sequence."""
|
||||||
def __init__(self, name, desc=None, sequence=None):
|
def __init__(self, name:str, desc:str=None, sequence=None):
|
||||||
self.sequence = sequence or []
|
self.sequence = sequence or []
|
||||||
self.name = name
|
self.name = name
|
||||||
self.desc = desc
|
self.desc = desc
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
member_strs = [str(x) for x in self.sequence]
|
member_strs = [str(x) for x in self.sequence]
|
||||||
return '%s(%s)' % (self.name, ','.join(member_strs))
|
return '%s(%s)' % (self.name, ','.join(member_strs))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
member_strs = [repr(x) for x in self.sequence]
|
member_strs = [repr(x) for x in self.sequence]
|
||||||
return '%s(%s)' % (self.__class__, ','.join(member_strs))
|
return '%s(%s)' % (self.__class__, ','.join(member_strs))
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other) -> 'DataObjectSequence':
|
||||||
"""Add (append) a DataObject or DataObjectChoice to the sequence."""
|
"""Add (append) a DataObject or DataObjectChoice to the sequence."""
|
||||||
if isinstance(other, 'DataObject'):
|
if isinstance(other, 'DataObject'):
|
||||||
return DataObjectSequence(self.name, self.desc, self.sequence + [other])
|
return DataObjectSequence(self.name, self.desc, self.sequence + [other])
|
||||||
|
@ -1421,7 +1423,7 @@ class DataObjectSequence:
|
||||||
return DataObjectSequence(self.name, self.desc, self.sequence + other.sequence)
|
return DataObjectSequence(self.name, self.desc, self.sequence + other.sequence)
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def decode(self, binary:bytes):
|
def decode(self, binary:bytes) -> Tuple[list, bytes]:
|
||||||
"""Decode a sequence by calling the decoder of each element in the sequence.
|
"""Decode a sequence by calling the decoder of each element in the sequence.
|
||||||
Args:
|
Args:
|
||||||
binary : binary bytes of encoded data
|
binary : binary bytes of encoded data
|
||||||
|
@ -1437,7 +1439,7 @@ class DataObjectSequence:
|
||||||
return (res, remainder)
|
return (res, remainder)
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def decode_multi(self, do:bytes):
|
def decode_multi(self, do:bytes) -> Tuple[list, bytes]:
|
||||||
"""Decode multiple occurrences of the sequence from the binary input data.
|
"""Decode multiple occurrences of the sequence from the binary input data.
|
||||||
Args:
|
Args:
|
||||||
do : binary input data to be decoded
|
do : binary input data to be decoded
|
||||||
|
@ -1458,7 +1460,7 @@ class DataObjectSequence:
|
||||||
return (res, remainder)
|
return (res, remainder)
|
||||||
|
|
||||||
# 'codec' interface
|
# 'codec' interface
|
||||||
def encode(self, decoded):
|
def encode(self, decoded) -> bytes:
|
||||||
"""Encode a sequence by calling the encoder of each element in the sequence."""
|
"""Encode a sequence by calling the encoder of each element in the sequence."""
|
||||||
encoded = bytearray()
|
encoded = bytearray()
|
||||||
i = 0
|
i = 0
|
||||||
|
|
Loading…
Reference in New Issue