foxglove-sdk 0.8.1__cp312-cp312-win32.whl → 0.16.3__cp312-cp312-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of foxglove-sdk might be problematic. Click here for more details.
- foxglove/__init__.py +245 -124
- foxglove/_foxglove_py/__init__.pyi +233 -167
- foxglove/_foxglove_py/channels.pyi +2792 -2580
- foxglove/_foxglove_py/cloud.pyi +9 -0
- foxglove/_foxglove_py/mcap.pyi +125 -84
- foxglove/_foxglove_py/schemas.pyi +1009 -839
- foxglove/_foxglove_py/schemas_wkt.pyi +85 -77
- foxglove/_foxglove_py/websocket.pyi +394 -343
- foxglove/_foxglove_py.cp312-win32.pyd +0 -0
- foxglove/benchmarks/test_mcap_serialization.py +160 -160
- foxglove/channel.py +241 -234
- foxglove/channels/__init__.py +94 -90
- foxglove/cloud.py +61 -0
- foxglove/mcap.py +12 -12
- foxglove/notebook/__init__.py +0 -0
- foxglove/notebook/foxglove_widget.py +100 -0
- foxglove/notebook/notebook_buffer.py +114 -0
- foxglove/schemas/__init__.py +163 -155
- foxglove/tests/test_channel.py +243 -215
- foxglove/tests/test_context.py +10 -0
- foxglove/tests/test_logging.py +62 -16
- foxglove/tests/test_mcap.py +477 -116
- foxglove/tests/test_parameters.py +178 -154
- foxglove/tests/test_schemas.py +17 -0
- foxglove/tests/test_server.py +141 -110
- foxglove/tests/test_time.py +137 -137
- foxglove/websocket.py +220 -195
- foxglove_sdk-0.16.3.dist-info/METADATA +53 -0
- foxglove_sdk-0.16.3.dist-info/RECORD +32 -0
- {foxglove_sdk-0.8.1.dist-info → foxglove_sdk-0.16.3.dist-info}/WHEEL +1 -1
- foxglove_sdk-0.8.1.dist-info/METADATA +0 -51
- foxglove_sdk-0.8.1.dist-info/RECORD +0 -25
|
Binary file
|
|
@@ -1,160 +1,160 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import math
|
|
3
|
-
import os
|
|
4
|
-
import struct
|
|
5
|
-
import time
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Generator, List
|
|
8
|
-
|
|
9
|
-
import pytest
|
|
10
|
-
from foxglove import Channel, open_mcap
|
|
11
|
-
from foxglove.channels import PointCloudChannel, SceneUpdateChannel
|
|
12
|
-
from foxglove.schemas import (
|
|
13
|
-
Color,
|
|
14
|
-
CubePrimitive,
|
|
15
|
-
Duration,
|
|
16
|
-
PackedElementField,
|
|
17
|
-
PackedElementFieldNumericType,
|
|
18
|
-
PointCloud,
|
|
19
|
-
Pose,
|
|
20
|
-
Quaternion,
|
|
21
|
-
SceneEntity,
|
|
22
|
-
SceneUpdate,
|
|
23
|
-
Vector3,
|
|
24
|
-
)
|
|
25
|
-
from pytest_benchmark.fixture import BenchmarkFixture # type: ignore
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@pytest.fixture
|
|
29
|
-
def tmp_mcap(tmpdir: os.PathLike[str]) -> Generator[Path, None, None]:
|
|
30
|
-
dir = Path(tmpdir)
|
|
31
|
-
mcap = dir / "test.mcap"
|
|
32
|
-
yield mcap
|
|
33
|
-
mcap.unlink()
|
|
34
|
-
dir.rmdir()
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def build_entities(entity_count: int) -> List[SceneEntity]:
|
|
38
|
-
assert entity_count > 0
|
|
39
|
-
return [
|
|
40
|
-
SceneEntity(
|
|
41
|
-
id=f"box_{i}",
|
|
42
|
-
frame_id="box",
|
|
43
|
-
lifetime=Duration(10, nsec=int(100 * 1e6)),
|
|
44
|
-
cubes=[
|
|
45
|
-
CubePrimitive(
|
|
46
|
-
pose=Pose(
|
|
47
|
-
position=Vector3(x=0.0, y=0.0, z=3.0),
|
|
48
|
-
orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0),
|
|
49
|
-
),
|
|
50
|
-
size=Vector3(x=1.0, y=1.0, z=1.0),
|
|
51
|
-
color=Color(r=1.0, g=0.0, b=0.0, a=1.0),
|
|
52
|
-
)
|
|
53
|
-
],
|
|
54
|
-
)
|
|
55
|
-
for i in range(entity_count)
|
|
56
|
-
]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def write_scene_entity_mcap(
|
|
60
|
-
tmp_mcap: Path, channel: SceneUpdateChannel, entities: List[SceneEntity]
|
|
61
|
-
) -> None:
|
|
62
|
-
with open_mcap(tmp_mcap, allow_overwrite=True):
|
|
63
|
-
for _ in range(100):
|
|
64
|
-
channel.log(SceneUpdate(entities=entities))
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def make_point_cloud(point_count: int) -> PointCloud:
|
|
68
|
-
"""
|
|
69
|
-
https://foxglove.dev/blog/visualizing-point-clouds-with-custom-colors
|
|
70
|
-
"""
|
|
71
|
-
point_struct = struct.Struct("<fffBBBB")
|
|
72
|
-
f32 = PackedElementFieldNumericType.Float32
|
|
73
|
-
u32 = PackedElementFieldNumericType.Uint32
|
|
74
|
-
|
|
75
|
-
t = time.time()
|
|
76
|
-
count = math.ceil(math.sqrt(point_count))
|
|
77
|
-
points = [
|
|
78
|
-
(x + math.cos(t + y / 5), y, 0) for x in range(count) for y in range(count)
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
buffer = bytearray(point_struct.size * len(points))
|
|
82
|
-
for i, point in enumerate(points):
|
|
83
|
-
x, y, z = point
|
|
84
|
-
r = g = b = a = 128
|
|
85
|
-
point_struct.pack_into(buffer, i * point_struct.size, x, y, z, b, g, r, a)
|
|
86
|
-
|
|
87
|
-
return PointCloud(
|
|
88
|
-
frame_id="points",
|
|
89
|
-
pose=Pose(
|
|
90
|
-
position=Vector3(x=0, y=0, z=0),
|
|
91
|
-
orientation=Quaternion(x=0, y=0, z=0, w=1),
|
|
92
|
-
),
|
|
93
|
-
point_stride=16, # 4 fields * 4 bytes
|
|
94
|
-
fields=[
|
|
95
|
-
PackedElementField(name="x", offset=0, type=f32),
|
|
96
|
-
PackedElementField(name="y", offset=4, type=f32),
|
|
97
|
-
PackedElementField(name="z", offset=8, type=f32),
|
|
98
|
-
PackedElementField(name="rgba", offset=12, type=u32),
|
|
99
|
-
],
|
|
100
|
-
data=bytes(buffer),
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def write_point_cloud_mcap(
|
|
105
|
-
tmp_mcap: Path, channel: PointCloudChannel, point_cloud: PointCloud
|
|
106
|
-
) -> None:
|
|
107
|
-
with open_mcap(tmp_mcap, allow_overwrite=True):
|
|
108
|
-
for _ in range(10):
|
|
109
|
-
channel.log(point_cloud)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def write_untyped_channel_mcap(
|
|
113
|
-
tmp_mcap: Path, channel: Channel, messages: List[bytes]
|
|
114
|
-
) -> None:
|
|
115
|
-
with open_mcap(tmp_mcap, allow_overwrite=True):
|
|
116
|
-
for message in messages:
|
|
117
|
-
channel.log(message)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@pytest.mark.benchmark
|
|
121
|
-
@pytest.mark.parametrize("entity_count", [1, 2, 4, 8])
|
|
122
|
-
def test_write_scene_update_mcap(
|
|
123
|
-
benchmark: BenchmarkFixture,
|
|
124
|
-
entity_count: int,
|
|
125
|
-
tmp_mcap: Path,
|
|
126
|
-
) -> None:
|
|
127
|
-
channel = SceneUpdateChannel(f"/scene_{entity_count}")
|
|
128
|
-
entities = build_entities(entity_count)
|
|
129
|
-
benchmark(write_scene_entity_mcap, tmp_mcap, channel, entities)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
@pytest.mark.benchmark
|
|
133
|
-
@pytest.mark.parametrize("point_count", [100, 1000, 10000])
|
|
134
|
-
def test_write_point_cloud_mcap(
|
|
135
|
-
benchmark: BenchmarkFixture,
|
|
136
|
-
point_count: int,
|
|
137
|
-
tmp_mcap: Path,
|
|
138
|
-
) -> None:
|
|
139
|
-
print("test_write_point_cloud_mcap")
|
|
140
|
-
channel = PointCloudChannel(f"/point_cloud_{point_count}")
|
|
141
|
-
point_cloud = make_point_cloud(point_count)
|
|
142
|
-
benchmark(write_point_cloud_mcap, tmp_mcap, channel, point_cloud)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
@pytest.mark.benchmark
|
|
146
|
-
@pytest.mark.parametrize("message_count", [10, 100, 1000])
|
|
147
|
-
def test_write_untyped_channel_mcap(
|
|
148
|
-
benchmark: BenchmarkFixture,
|
|
149
|
-
message_count: int,
|
|
150
|
-
tmp_mcap: Path,
|
|
151
|
-
) -> None:
|
|
152
|
-
channel = Channel(
|
|
153
|
-
f"/untyped_{message_count}",
|
|
154
|
-
schema={"type": "object", "additionalProperties": True},
|
|
155
|
-
)
|
|
156
|
-
messages = [
|
|
157
|
-
json.dumps({"message": f"hello_{i}"}).encode("utf-8")
|
|
158
|
-
for i in range(message_count)
|
|
159
|
-
]
|
|
160
|
-
benchmark(write_untyped_channel_mcap, tmp_mcap, channel, messages)
|
|
1
|
+
import json
|
|
2
|
+
import math
|
|
3
|
+
import os
|
|
4
|
+
import struct
|
|
5
|
+
import time
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Generator, List
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
from foxglove import Channel, open_mcap
|
|
11
|
+
from foxglove.channels import PointCloudChannel, SceneUpdateChannel
|
|
12
|
+
from foxglove.schemas import (
|
|
13
|
+
Color,
|
|
14
|
+
CubePrimitive,
|
|
15
|
+
Duration,
|
|
16
|
+
PackedElementField,
|
|
17
|
+
PackedElementFieldNumericType,
|
|
18
|
+
PointCloud,
|
|
19
|
+
Pose,
|
|
20
|
+
Quaternion,
|
|
21
|
+
SceneEntity,
|
|
22
|
+
SceneUpdate,
|
|
23
|
+
Vector3,
|
|
24
|
+
)
|
|
25
|
+
from pytest_benchmark.fixture import BenchmarkFixture # type: ignore
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def tmp_mcap(tmpdir: os.PathLike[str]) -> Generator[Path, None, None]:
|
|
30
|
+
dir = Path(tmpdir)
|
|
31
|
+
mcap = dir / "test.mcap"
|
|
32
|
+
yield mcap
|
|
33
|
+
mcap.unlink()
|
|
34
|
+
dir.rmdir()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def build_entities(entity_count: int) -> List[SceneEntity]:
|
|
38
|
+
assert entity_count > 0
|
|
39
|
+
return [
|
|
40
|
+
SceneEntity(
|
|
41
|
+
id=f"box_{i}",
|
|
42
|
+
frame_id="box",
|
|
43
|
+
lifetime=Duration(10, nsec=int(100 * 1e6)),
|
|
44
|
+
cubes=[
|
|
45
|
+
CubePrimitive(
|
|
46
|
+
pose=Pose(
|
|
47
|
+
position=Vector3(x=0.0, y=0.0, z=3.0),
|
|
48
|
+
orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0),
|
|
49
|
+
),
|
|
50
|
+
size=Vector3(x=1.0, y=1.0, z=1.0),
|
|
51
|
+
color=Color(r=1.0, g=0.0, b=0.0, a=1.0),
|
|
52
|
+
)
|
|
53
|
+
],
|
|
54
|
+
)
|
|
55
|
+
for i in range(entity_count)
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def write_scene_entity_mcap(
|
|
60
|
+
tmp_mcap: Path, channel: SceneUpdateChannel, entities: List[SceneEntity]
|
|
61
|
+
) -> None:
|
|
62
|
+
with open_mcap(tmp_mcap, allow_overwrite=True):
|
|
63
|
+
for _ in range(100):
|
|
64
|
+
channel.log(SceneUpdate(entities=entities))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def make_point_cloud(point_count: int) -> PointCloud:
|
|
68
|
+
"""
|
|
69
|
+
https://foxglove.dev/blog/visualizing-point-clouds-with-custom-colors
|
|
70
|
+
"""
|
|
71
|
+
point_struct = struct.Struct("<fffBBBB")
|
|
72
|
+
f32 = PackedElementFieldNumericType.Float32
|
|
73
|
+
u32 = PackedElementFieldNumericType.Uint32
|
|
74
|
+
|
|
75
|
+
t = time.time()
|
|
76
|
+
count = math.ceil(math.sqrt(point_count))
|
|
77
|
+
points = [
|
|
78
|
+
(x + math.cos(t + y / 5), y, 0) for x in range(count) for y in range(count)
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
buffer = bytearray(point_struct.size * len(points))
|
|
82
|
+
for i, point in enumerate(points):
|
|
83
|
+
x, y, z = point
|
|
84
|
+
r = g = b = a = 128
|
|
85
|
+
point_struct.pack_into(buffer, i * point_struct.size, x, y, z, b, g, r, a)
|
|
86
|
+
|
|
87
|
+
return PointCloud(
|
|
88
|
+
frame_id="points",
|
|
89
|
+
pose=Pose(
|
|
90
|
+
position=Vector3(x=0, y=0, z=0),
|
|
91
|
+
orientation=Quaternion(x=0, y=0, z=0, w=1),
|
|
92
|
+
),
|
|
93
|
+
point_stride=16, # 4 fields * 4 bytes
|
|
94
|
+
fields=[
|
|
95
|
+
PackedElementField(name="x", offset=0, type=f32),
|
|
96
|
+
PackedElementField(name="y", offset=4, type=f32),
|
|
97
|
+
PackedElementField(name="z", offset=8, type=f32),
|
|
98
|
+
PackedElementField(name="rgba", offset=12, type=u32),
|
|
99
|
+
],
|
|
100
|
+
data=bytes(buffer),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def write_point_cloud_mcap(
|
|
105
|
+
tmp_mcap: Path, channel: PointCloudChannel, point_cloud: PointCloud
|
|
106
|
+
) -> None:
|
|
107
|
+
with open_mcap(tmp_mcap, allow_overwrite=True):
|
|
108
|
+
for _ in range(10):
|
|
109
|
+
channel.log(point_cloud)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def write_untyped_channel_mcap(
|
|
113
|
+
tmp_mcap: Path, channel: Channel, messages: List[bytes]
|
|
114
|
+
) -> None:
|
|
115
|
+
with open_mcap(tmp_mcap, allow_overwrite=True):
|
|
116
|
+
for message in messages:
|
|
117
|
+
channel.log(message)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@pytest.mark.benchmark
|
|
121
|
+
@pytest.mark.parametrize("entity_count", [1, 2, 4, 8])
|
|
122
|
+
def test_write_scene_update_mcap(
|
|
123
|
+
benchmark: BenchmarkFixture,
|
|
124
|
+
entity_count: int,
|
|
125
|
+
tmp_mcap: Path,
|
|
126
|
+
) -> None:
|
|
127
|
+
channel = SceneUpdateChannel(f"/scene_{entity_count}")
|
|
128
|
+
entities = build_entities(entity_count)
|
|
129
|
+
benchmark(write_scene_entity_mcap, tmp_mcap, channel, entities)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@pytest.mark.benchmark
|
|
133
|
+
@pytest.mark.parametrize("point_count", [100, 1000, 10000])
|
|
134
|
+
def test_write_point_cloud_mcap(
|
|
135
|
+
benchmark: BenchmarkFixture,
|
|
136
|
+
point_count: int,
|
|
137
|
+
tmp_mcap: Path,
|
|
138
|
+
) -> None:
|
|
139
|
+
print("test_write_point_cloud_mcap")
|
|
140
|
+
channel = PointCloudChannel(f"/point_cloud_{point_count}")
|
|
141
|
+
point_cloud = make_point_cloud(point_count)
|
|
142
|
+
benchmark(write_point_cloud_mcap, tmp_mcap, channel, point_cloud)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@pytest.mark.benchmark
|
|
146
|
+
@pytest.mark.parametrize("message_count", [10, 100, 1000])
|
|
147
|
+
def test_write_untyped_channel_mcap(
|
|
148
|
+
benchmark: BenchmarkFixture,
|
|
149
|
+
message_count: int,
|
|
150
|
+
tmp_mcap: Path,
|
|
151
|
+
) -> None:
|
|
152
|
+
channel = Channel(
|
|
153
|
+
f"/untyped_{message_count}",
|
|
154
|
+
schema={"type": "object", "additionalProperties": True},
|
|
155
|
+
)
|
|
156
|
+
messages = [
|
|
157
|
+
json.dumps({"message": f"hello_{i}"}).encode("utf-8")
|
|
158
|
+
for i in range(message_count)
|
|
159
|
+
]
|
|
160
|
+
benchmark(write_untyped_channel_mcap, tmp_mcap, channel, messages)
|