Skip to content

Commit af57394

Browse files
committed
fix(python): default LidarData point_cloud/segmentation to lists
Match C++ LidarData (vector point_cloud + vector segmentation). Scalar defaults made len()/slice paths in sample lidar clients raise TypeError before any RPC payload was applied. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
1 parent d109f0d commit af57394

3 files changed

Lines changed: 60 additions & 2 deletions

File tree

‎PythonClient/airsim/types.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,10 +415,13 @@ class CameraInfo(MsgpackMixin):
415415
proj_mat = ProjectionMatrix()
416416

417417
class LidarData(MsgpackMixin):
418-
point_cloud = 0.0
418+
# C++ SoT: vector<real_T> point_cloud + vector<int> segmentation
419+
# (see CommonStructs.hpp / RpcLibAdaptorsBase). Defaults must be lists so
420+
# clients can len()/slice before any RPC payload is applied.
421+
point_cloud = []
419422
time_stamp = np.uint64(0)
420423
pose = Pose()
421-
segmentation = 0
424+
segmentation = []
422425

423426
class ImuData(MsgpackMixin):
424427
time_stamp = np.uint64(0)

‎PythonClient/tests/__init__.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Offline PythonClient unit tests (no AirSim sim required).
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""Offline checks for LidarData list field defaults (no AirSim sim required)."""
2+
from __future__ import annotations
3+
4+
import importlib.util
5+
import sys
6+
import types
7+
import unittest
8+
from pathlib import Path
9+
10+
11+
def _load_types():
12+
# Stub msgpackrpc so types.py imports cleanly without the RPC package.
13+
if "msgpackrpc" not in sys.modules:
14+
sys.modules["msgpackrpc"] = types.ModuleType("msgpackrpc")
15+
root = Path(__file__).resolve().parents[1] / "airsim" / "types.py"
16+
spec = importlib.util.spec_from_file_location("airsim_types_under_test", root)
17+
mod = importlib.util.module_from_spec(spec)
18+
assert spec.loader is not None
19+
spec.loader.exec_module(mod)
20+
return mod
21+
22+
23+
class TestLidarDataTypes(unittest.TestCase):
24+
@classmethod
25+
def setUpClass(cls):
26+
cls.types = _load_types()
27+
28+
def test_defaults_are_empty_lists(self):
29+
data = self.types.LidarData()
30+
self.assertIsInstance(data.point_cloud, list)
31+
self.assertIsInstance(data.segmentation, list)
32+
self.assertEqual(len(data.point_cloud), 0)
33+
self.assertEqual(len(data.segmentation), 0)
34+
# Historical bug: scalar defaults break sample len()/slice code paths.
35+
self.assertFalse(isinstance(data.point_cloud, float))
36+
self.assertFalse(isinstance(data.segmentation, int))
37+
38+
def test_assign_point_cloud_and_segmentation(self):
39+
data = self.types.LidarData()
40+
data.point_cloud = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
41+
data.segmentation = [10, 20]
42+
self.assertEqual(len(data.point_cloud), 6)
43+
self.assertEqual(data.point_cloud[0:3], [1.0, 2.0, 3.0])
44+
self.assertEqual(data.segmentation, [10, 20])
45+
# Triplet walk matches public sample clients (drone_lidar / point_cloud).
46+
triplets = [
47+
data.point_cloud[i : i + 3]
48+
for i in range(0, len(data.point_cloud), 3)
49+
]
50+
self.assertEqual(triplets, [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
51+
52+
53+
if __name__ == "__main__":
54+
unittest.main()

0 commit comments

Comments
 (0)