Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
class TestStruct1(t.Struct):
b: typing.Optional[t.uint8_t]
a: t.uint8_t
with pytest.raises(TypeError):
class TestStruct2(t.Struct):
b: typing.Optional[t.uint8_t]
a: t.uint8_t
c: typing.Optional[t.uint8_t]
# Every field must be annotated
with pytest.raises(TypeError):
class BadTestStruct3(t.Struct):
a = 5
# In-class constants are allowed
class TestStruct3(t.Struct):
CONSTANT1: int = 123
CONSTANT2 = 1234
_private1: int = 456
_private2 = 4567
assert not TestStruct3.fields()
assert TestStruct3.CONSTANT1 == 123
assert TestStruct3.CONSTANT2 == 1234
assert TestStruct3._private1 == 456
assert TestStruct3._private2 == 4567
# This is fine
pass
# Fields cannot have values
with pytest.raises(TypeError):
class TestStruct6(t.Struct):
a: t.uint8_t = 2
# unless they are a StructField
class TestStruct7(t.Struct):
a: t.uint8_t = t.StructField()
# Fields can only have a single concrete type
with pytest.raises(TypeError):
class TestStruct8(t.Struct):
bad: typing.Union[t.uint8_t, t.uint16_t]
def test_old_style_struct():
with pytest.raises(TypeError):
# `_fields` would typically be ignored but this would be very bad
class OldStruct(t.Struct):
_fields = [("foo", t.uint8_t)]
def test_nested_structs():
class InnerStruct(t.Struct):
b: t.uint8_t
c: t.uint8_t
class OuterStruct(t.Struct):
a: t.uint8_t
inner: typing.Optional[InnerStruct]
d: typing.Optional[t.uint8_t]
s1, remaining = OuterStruct.deserialize(b"\x00\x01\x02")
assert not remaining
assert s1.a == 0
assert s1.inner.b == 1
assert s1.inner.c == 2
assert s1.d is None
s2, remaining = OuterStruct.deserialize(b"\x00\x01\x02\x03")
assert not remaining
assert s2.a == 0
assert s2.inner.b == 1
assert s2.inner.c == 2
def test_struct_subclass_extension(data):
class TestStruct(t.Struct):
foo: t.uint8_t
class TestStructSubclass(TestStruct):
bar: t.uint8_t = t.StructField(requires=lambda s: s.foo == 0x01)
class TestCombinedStruct(t.Struct):
foo: t.uint8_t
bar: t.uint8_t = t.StructField(requires=lambda s: s.foo == 0x01)
assert len(TestStructSubclass.fields()) == 2
assert len(TestCombinedStruct.fields()) == 2
error1 = None
error2 = None
try:
ts1, remaining1 = TestStructSubclass.deserialize(data)
except Exception as e:
error1 = e
try:
ts2, remaining2 = TestCombinedStruct.deserialize(data)
direction: t.uint8_t
attrid: t.uint16_t
class DiscoverAttributesResponseRecord(t.Struct):
attrid: t.uint16_t
datatype: t.uint8_t
class AttributeAccessControl(t.bitmap8):
READ = 0x01
WRITE = 0x02
REPORT = 0x04
class DiscoverAttributesExtendedResponseRecord(t.Struct):
attrid: t.uint16_t
datatype: t.uint8_t
acl: AttributeAccessControl
class Command(t.enum8):
"""ZCL Foundation Global Command IDs."""
Read_Attributes = 0x00
Read_Attributes_rsp = 0x01
Write_Attributes = 0x02
Write_Attributes_Undivided = 0x03
Write_Attributes_rsp = 0x04
Write_Attributes_No_Response = 0x05
Configure_Reporting = 0x06
Configure_Reporting_rsp = 0x07
import typing
import zigpy.types as t
class PowerDescriptor(t.Struct):
byte_1: t.uint8_t
byte_2: t.uint8_t
# TODO: interpret the four 4-bit fields
class SimpleDescriptor(t.Struct):
endpoint: t.uint8_t
profile: t.uint16_t
device_type: t.uint16_t
device_version: t.uint8_t
input_clusters: t.LVList(t.uint16_t)
output_clusters: t.LVList(t.uint16_t)
class SizePrefixedSimpleDescriptor(SimpleDescriptor):
def serialize(self):
data = super().serialize()
return len(data).to_bytes(1, "little") + data
@classmethod
def deserialize(cls, data):
if not data or data[0] == 0:
class Route(t.Struct):
"""Route Descriptor"""
DstNWK: t.NWK
RouteStatus: t.uint8_t
NextHop: t.NWK
class Routes(t.Struct):
Entries: t.uint8_t
StartIndex: t.uint8_t
RoutingTableList: t.LVList(Route)
class NwkUpdate(t.Struct):
CHANNEL_CHANGE_REQ = 0xFE
CHANNEL_MASK_MANAGER_ADDR_CHANGE_REQ = 0xFF
ScanChannels: t.Channels
ScanDuration: t.uint8_t
ScanCount: t.uint8_t
nwkUpdateId: t.uint8_t
nwkManagerAddr: t.NWK
def serialize(self) -> bytes:
"""Serialize data."""
r = self.ScanChannels.serialize() + self.ScanDuration.serialize()
if self.ScanDuration <= 0x05:
r += self.ScanCount.serialize()
if self.ScanDuration in (
self.CHANNEL_CHANGE_REQ,
r += " direction=%s attrid=%s" % (self.direction, self.attrid)
r += ">"
return r
class ConfigureReportingResponse(t.List(ConfigureReportingResponseRecord)):
def serialize(self):
failed = [record for record in self if record.status != Status.SUCCESS]
if failed:
return b"".join(
[ConfigureReportingResponseRecord(i).serialize() for i in failed]
)
return Status.SUCCESS.serialize()
class ReadReportingConfigRecord(t.Struct):
direction: t.uint8_t
attrid: t.uint16_t
class DiscoverAttributesResponseRecord(t.Struct):
attrid: t.uint16_t
datatype: t.uint8_t
class AttributeAccessControl(t.bitmap8):
READ = 0x01
WRITE = 0x02
REPORT = 0x04
class DiscoverAttributesExtendedResponseRecord(t.Struct):
"""Mgmt_Lqi_rsp"""
Entries: t.uint8_t
StartIndex: t.uint8_t
NeighborTableList: t.LVList(Neighbor)
class Route(t.Struct):
"""Route Descriptor"""
DstNWK: t.NWK
RouteStatus: t.uint8_t
NextHop: t.NWK
class Routes(t.Struct):
Entries: t.uint8_t
StartIndex: t.uint8_t
RoutingTableList: t.LVList(Route)
class NwkUpdate(t.Struct):
CHANNEL_CHANGE_REQ = 0xFE
CHANNEL_MASK_MANAGER_ADDR_CHANGE_REQ = 0xFF
ScanChannels: t.Channels
ScanDuration: t.uint8_t
ScanCount: t.uint8_t
nwkUpdateId: t.uint8_t
nwkManagerAddr: t.NWK
def serialize(self) -> bytes: