Skip to content

Commit

Permalink
enhance exception handling in val2bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
semuadmin committed Jan 1, 2025
1 parent 7ee0fdb commit 6e48a39
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/checkpr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9, "3.10", "3.11", "3.12", "3.13.0-rc.3"]
python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9, "3.10", "3.11", "3.12", "3.13.0-rc.3"]
python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4
Expand Down
28 changes: 20 additions & 8 deletions src/pyubx2/ubxhelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import pyubx2.ubxtypes_configdb as ubcdb
import pyubx2.ubxtypes_core as ubt
from pyubx2.ubxtypes_core import (
ATTTYPE,
NMEA_PROTOCOL,
POLL,
RTCM3_PROTOCOL,
Expand Down Expand Up @@ -125,11 +126,13 @@ def attsiz(att: str) -> int:
Helper function to return attribute size in bytes.
:param str: attribute type e.g. 'U002'
:return: size of attribute in bytes
:return: size of attribute in bytes, or -1 if variable length
:rtype: int
"""

if att == "CH": # variable length
return -1
return int(att[1:4])


Expand Down Expand Up @@ -274,11 +277,22 @@ def val2bytes(val, att: str) -> bytes:
"""

if att == ubt.CH: # single variable-length string (e.g. INF-NOTICE)
return val.encode("utf-8", "backslashreplace")
try:
if not isinstance(val, ATTTYPE[atttyp(att)]):
raise TypeError(
f"Attribute type {att} value {val} must be {ATTTYPE[atttyp(att)]}, not {type(val)}"
)
except KeyError as err:
raise ube.UBXTypeError(f"Unknown attribute type {att}") from err

atts = attsiz(att)
if atttyp(att) in ("C", "X"): # byte or char
if atttyp(att) == "X": # byte
valb = val
elif atttyp(att) == "C": # char
if isinstance(val, str):
valb = val.encode("utf-8", "backslashreplace")
else: # byte
valb = val
elif atttyp(att) in ("E", "L", "U"): # unsigned integer
valb = val.to_bytes(atts, byteorder="little", signed=False)
elif atttyp(att) == "A": # array of unsigned integers
Expand All @@ -289,11 +303,9 @@ def val2bytes(val, att: str) -> bytes:
elif atttyp(att) == "I": # signed integer
valb = val.to_bytes(atts, byteorder="little", signed=True)
elif att == ubt.R4: # single precision floating point
valb = struct.pack("<f", val)
valb = struct.pack("<f", float(val))
elif att == ubt.R8: # double precision floating point
valb = struct.pack("<d", val)
else:
raise ube.UBXTypeError(f"Unknown attribute type {att}")
valb = struct.pack("<d", float(val))
return valb


Expand Down
6 changes: 0 additions & 6 deletions src/pyubx2/ubxmessage.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from pyubx2.exceptions import UBXMessageError, UBXTypeError
from pyubx2.ubxhelpers import (
attsiz,
atttyp,
bytes2val,
calc_checksum,
cfgkey2name,
Expand All @@ -30,7 +29,6 @@
nomval,
val2bytes,
)
from pyubx2.ubxtypes_configdb import CFDBTYPE
from pyubx2.ubxtypes_core import (
CH,
GET,
Expand Down Expand Up @@ -740,10 +738,6 @@ def config_set(layers: int, transaction: int, cfgData: list) -> object:
else:
kid = key
(key, att) = cfgkey2name(key) # lookup attribute type
if type(val) != CFDBTYPE[atttyp(att)]:
raise TypeError(
f"Configuration {kid:#08x} ({key}) value {val} must be {CFDBTYPE[atttyp(att)]}, not {type(val)}"
)
keyb = val2bytes(kid, U4)
valb = val2bytes(val, att)
lis = lis + keyb + valb
Expand Down
11 changes: 0 additions & 11 deletions src/pyubx2/ubxtypes_configdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,6 @@
L,
)

CFDBTYPE = {
"C": type(b"0"),
"E": type(0),
"I": type(0),
"L": type(0),
"R": type(0.1),
"U": type(0),
"X": type(b"0"),
}
"""Configuration Ddtabase permissible attribute types"""

# memory layer designators for CFG_VALSET & CFG_VALDEL
SET_LAYER_RAM = 1
"""Set RAM (volatile) memory layer in UBX-CFG-VALSET, UBX-CFG-VALDEL"""
Expand Down
12 changes: 12 additions & 0 deletions src/pyubx2/ubxtypes_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@
R4 = "R004" # Float (IEEE 754) Single Precision 4 bytes
R8 = "R008" # Float (IEEE 754) Double Precision 8 bytes

ATTTYPE = {
"A": type([0, 1]),
"C": (type(b"0"), type("0")),
"E": type(0),
"I": type(0),
"L": type(0),
"R": (type(0), type(0.1)),
"U": type(0),
"X": type(b"0"),
}
"""Permissible attribute types"""

# ***********************************************
# THESE ARE THE UBX PROTOCOL CORE MESSAGE CLASSES
# ***********************************************
Expand Down
4 changes: 3 additions & 1 deletion src/pyubx2/ubxtypes_poll.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
UBX Protocol POLL payload definitions.
THESE ARE THE PAYLOAD DEFINITIONS FOR _POLL_ MESSAGES _TO_ THE RECEIVER
(e.g. query configuration; request monitoring, receiver management, logging or sensor fusion status).
(e.g. query configuration; request monitoring, receiver management,
logging or sensor fusion status).
Response payloads are defined in UBX_PAYLOADS_GET.
NB: Attribute names must be unique within each message class/id
Expand Down
12 changes: 11 additions & 1 deletion tests/test_configdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import unittest

from pyubx2 import UBXMessage, SET, POLL
from pyubx2 import UBXMessage, SET, POLL, SET_LAYER_FLASH, TXN_NONE
from pyubx2.ubxtypes_configdb import UBX_CONFIG_DATABASE
from tests.configdb_baseline import UBX_CONFIG_DATABASE_BASELINE

Expand Down Expand Up @@ -63,6 +63,16 @@ def testFill_CFGVALSET(self): # test CFG-VALSET SET constructor
)
self.assertEqual(str(res), EXPECTED_RESULT)

def testGOODConfigSet(self):
EXPECTED_RESULT = "<UBX(CFG-VALSET, version=0, ram=0, bbr=0, flash=1, action=0, reserved0=0, CFG_NAVSPG_USRDAT_ROTZ=0.0, CFG_NAVSPG_USRDAT_ROTY=0.10000000149011612)>"
msg = UBXMessage.config_set(
layers=SET_LAYER_FLASH,
transaction=TXN_NONE,
cfgData=[(0x40110069, 0), (0x40110068, 0.1)],
)
# print(msg)
self.assertEqual(str(msg), EXPECTED_RESULT)


if __name__ == "__main__":
# import sys;sys.argv = ['', 'Test.testName']
Expand Down
6 changes: 6 additions & 0 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,12 @@ def testBADConfigSet(self): # test invalid configuration database value type
transaction=TXN_NONE,
cfgData=[(0x5005002A, b"\x00")],
)
with self.assertRaises(TypeError):
UBXMessage.config_set(
layers=SET_LAYER_FLASH,
transaction=TXN_NONE,
cfgData=[(0x40110069, 0.1), (0x40110068, "0")],
)


if __name__ == "__main__":
Expand Down
5 changes: 5 additions & 0 deletions tests/test_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import pyubx2.ubxtypes_core as ubt
from pyubx2 import POLL, SET, UBX_CLASSES, UBXMessage, UBXReader
from pyubx2.ubxhelpers import (
attsiz,
att2idx,
att2name,
bytes2val,
Expand Down Expand Up @@ -258,6 +259,10 @@ def testhextable(self): # test hextable*( method)
res = hextable(b"$GNGLL,5327.04319,S,00214.41396,E,223232.00,A,A*68\r\n", 8)
self.assertEqual(res, EXPECTED_RESULT)

def testattsiz(self): # test attsiz
self.assertEqual(attsiz("CH"), -1)
self.assertEqual(attsiz("C032"), 32)

def testatt2idx(self): # test att2idx
EXPECTED_RESULT = [4, 16, 101, 0, (3, 6), 0]
atts = ["svid_04", "gnssId_16", "cno_101", "gmsLon", "gnod_03_06", "dodgy_xx"]
Expand Down

0 comments on commit 6e48a39

Please sign in to comment.