current-data-py 0.1.0__tar.gz → 0.1.2__tar.gz

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.
Files changed (80) hide show
  1. {current_data_py-0.1.0 → current_data_py-0.1.2}/MANIFEST.in +1 -0
  2. current_data_py-0.1.2/PKG-INFO +154 -0
  3. current_data_py-0.1.2/README.md +142 -0
  4. {current_data_py-0.1.0 → current_data_py-0.1.2}/__init__.py +1 -1
  5. current_data_py-0.1.2/current_data_py.egg-info/PKG-INFO +154 -0
  6. current_data_py-0.1.2/current_data_py.egg-info/SOURCES.txt +33 -0
  7. current_data_py-0.1.2/current_data_py.egg-info/requires.txt +6 -0
  8. current_data_py-0.1.2/examples/__init__.py +1 -0
  9. current_data_py-0.1.2/examples/list_schemas.py +7 -0
  10. current_data_py-0.1.2/examples/read_remote_td.py +48 -0
  11. {current_data_py-0.1.0 → current_data_py-0.1.2/examples}/read_td.py +1 -1
  12. {current_data_py-0.1.0 → current_data_py-0.1.2/examples}/write_td.py +2 -2
  13. current_data_py-0.1.2/proto_gen/python/management/metadata/metadata_pb2.py +38 -0
  14. current_data_py-0.1.2/proto_gen/python/management/service/service_pb2.py +64 -0
  15. current_data_py-0.1.2/proto_gen/python/management/service/service_pb2_grpc.py +330 -0
  16. current_data_py-0.1.2/proto_gen/python/msg/foxglove/compressed_audio_pb2.py +27 -0
  17. {current_data_py-0.1.0 → current_data_py-0.1.2}/pyproject.toml +5 -2
  18. current_data_py-0.1.2/remote/__init__.py +7 -0
  19. current_data_py-0.1.2/remote/client.py +85 -0
  20. current_data_py-0.1.2/remote/source.py +97 -0
  21. current_data_py-0.1.2/schema/__init__.py +99 -0
  22. {current_data_py-0.1.0 → current_data_py-0.1.2/schema}/message_metadata.py +1 -2
  23. {current_data_py-0.1.0 → current_data_py-0.1.2}/setup.py +10 -10
  24. {current_data_py-0.1.0 → current_data_py-0.1.2}/tests/check_package.py +2 -3
  25. current_data_py-0.1.2/tests/check_remote.py +172 -0
  26. current_data_py-0.1.0/PKG-INFO +0 -70
  27. current_data_py-0.1.0/README.md +0 -61
  28. current_data_py-0.1.0/current_data_py.egg-info/PKG-INFO +0 -70
  29. current_data_py-0.1.0/current_data_py.egg-info/SOURCES.txt +0 -20
  30. current_data_py-0.1.0/current_data_py.egg-info/requires.txt +0 -2
  31. current_data_py-0.1.0/schema.py +0 -102
  32. {current_data_py-0.1.0 → current_data_py-0.1.2}/current_data_py.egg-info/dependency_links.txt +0 -0
  33. {current_data_py-0.1.0 → current_data_py-0.1.2}/current_data_py.egg-info/top_level.txt +0 -0
  34. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/builtin_interfaces/duration_pb2.py +0 -0
  35. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/builtin_interfaces/time_pb2.py +0 -0
  36. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/custom_msgs/joint_current_pb2.py +0 -0
  37. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/foxglove/compressed_video_pb2.py +0 -0
  38. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/point32_pb2.py +0 -0
  39. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/point_pb2.py +0 -0
  40. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/pose_pb2.py +0 -0
  41. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/pose_stamped_pb2.py +0 -0
  42. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/pose_with_covariance_pb2.py +0 -0
  43. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/pose_with_covariance_stamped_pb2.py +0 -0
  44. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/quaternion_pb2.py +0 -0
  45. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/transform_pb2.py +0 -0
  46. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/transform_stamped_pb2.py +0 -0
  47. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/twist_pb2.py +0 -0
  48. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/twist_stamped_pb2.py +0 -0
  49. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/twist_with_covariance_pb2.py +0 -0
  50. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/twist_with_covariance_stamped_pb2.py +0 -0
  51. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/vector3_pb2.py +0 -0
  52. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/wrench_pb2.py +0 -0
  53. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/geometry_msgs/wrench_stamped_pb2.py +0 -0
  54. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/nav_msgs/map_meta_data_pb2.py +0 -0
  55. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/nav_msgs/occupancy_grid_pb2.py +0 -0
  56. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/nav_msgs/odometry_pb2.py +0 -0
  57. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/nav_msgs/path_pb2.py +0 -0
  58. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/battery_state_pb2.py +0 -0
  59. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/camera_info_pb2.py +0 -0
  60. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/compressed_image_pb2.py +0 -0
  61. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/image_pb2.py +0 -0
  62. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/imu_pb2.py +0 -0
  63. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/joint_state_pb2.py +0 -0
  64. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/laser_scan_pb2.py +0 -0
  65. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/nav_sat_fix_pb2.py +0 -0
  66. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/nav_sat_status_pb2.py +0 -0
  67. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/point_cloud2_pb2.py +0 -0
  68. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/point_field_pb2.py +0 -0
  69. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/range_pb2.py +0 -0
  70. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/sensor_msgs/region_of_interest_pb2.py +0 -0
  71. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/std_msgs/bool_pb2.py +0 -0
  72. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/std_msgs/color_rgba_pb2.py +0 -0
  73. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/std_msgs/float32_pb2.py +0 -0
  74. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/std_msgs/float64_pb2.py +0 -0
  75. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/std_msgs/header_pb2.py +0 -0
  76. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/std_msgs/int32_pb2.py +0 -0
  77. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/std_msgs/string_pb2.py +0 -0
  78. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/std_msgs/uint32_pb2.py +0 -0
  79. {current_data_py-0.1.0 → current_data_py-0.1.2}/proto_gen/python/msg/tf2_msgs/tf_message_pb2.py +0 -0
  80. {current_data_py-0.1.0 → current_data_py-0.1.2}/setup.cfg +0 -0
@@ -1 +1,2 @@
1
1
  include tests/check_package.py
2
+ include tests/check_remote.py
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: current-data-py
3
+ Version: 0.1.2
4
+ Summary: Current Data protobuf messages and schema metadata
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: protobuf>=3.20
8
+ Requires-Dist: turbodata==0.1.0
9
+ Provides-Extra: remote
10
+ Requires-Dist: grpcio>=1.51.1; extra == "remote"
11
+ Requires-Dist: alibabacloud-oss-v2<2,>=1.4.0; extra == "remote"
12
+
13
+ # current-data-py
14
+
15
+ Current Data protobuf messages and schema metadata. Requires Python 3.9+.
16
+
17
+ ```bash
18
+ pip install current-data-py
19
+ ```
20
+
21
+ ```python
22
+ from current_data_py import SCHEMA_TO_CLASS, descriptor_set, topic_metadata
23
+ from current_data_py.schema import Pose
24
+
25
+ message = Pose()
26
+ message.position.y = 1.0
27
+ metadata = topic_metadata(Pose)
28
+ decoded = SCHEMA_TO_CLASS[metadata["schema_name"]].FromString(message.SerializeToString())
29
+ ```
30
+
31
+ TD examples write/read a Pose on `/head/pose/command`:
32
+
33
+ ```bash
34
+ python -m current_data_py.examples.write_td example.td
35
+ python -m current_data_py.examples.read_td example.td
36
+ ```
37
+
38
+ ## Layout
39
+
40
+ - `schema/`: message classes, schema registry and protobuf metadata helpers.
41
+ - `examples/`: runnable TD reading/writing and schema-listing examples.
42
+ - `remote/`: gRPC client/credential handling in `client.py`, OSS Range source in `source.py`.
43
+ - `tests/`: installed-package, distribution and remote integration checks.
44
+ - Root: package exports and build configuration.
45
+
46
+ `current_data_py.schema` and `current_data_py.remote` imports are preserved.
47
+ Metadata helpers also remain available from `current_data_py`; their module is
48
+ now `current_data_py.schema.message_metadata`. Run examples with
49
+ `python -m current_data_py.examples.read_td`, `write_td` or `list_schemas`.
50
+ Generated protobuf sources stay in the shared `proto_gen/python` tree and are
51
+ bundled under the private `_proto` namespace during packaging.
52
+
53
+ ## Development and releases
54
+
55
+ Packaging configuration lives in `current_data_py/`. Generated messages live
56
+ only in the repository's `proto_gen/python` (message schemas in `msg/`,
57
+ management RPC bindings in `management/`). Regenerate them using the existing
58
+ `proto/generate.sh` workflow after changing their proto definitions. Python RPC
59
+ generation uses `protoc` and `grpc_python_plugin` (tested with 3.21.12 and 1.51.1);
60
+ these are development tools and are not required when installing the package.
61
+ The build reads those files and adjusts their Python imports in the build
62
+ directory, placing them under `current_data_py._proto` in the wheel.
63
+ It does not modify or duplicate generated sources in the checkout.
64
+ The source distribution includes the original generated files so it can also
65
+ build without `protoc`. Installation requires neither the repository nor `protoc`.
66
+
67
+ ```bash
68
+ cd current_data_py # from the repository root
69
+ python -m pip install build twine
70
+ python -m build
71
+ python -m twine check dist/*
72
+ python tests/check_distribution.py
73
+ ```
74
+
75
+ Artifacts are written to `current_data_py/dist/`. The build adds the shared
76
+ protobuf inputs to the source archive without copying them into this directory.
77
+
78
+ For development, use a regular `pip install .` and run from outside the checkout;
79
+ reinstall after changes. Editable installs are not supported by this build step.
80
+
81
+ Install the wheel in a fresh environment and run
82
+ `python /absolute/path/to/current_data_py/tests/check_package.py` from outside
83
+ the repository. Use a clean `dist` for each release and increment the version
84
+ in `pyproject.toml`. Confirm the package name, license and supported Python
85
+ versions before publishing. No license has been selected yet.
86
+
87
+ ```bash
88
+ python -m twine upload --repository testpypi dist/*
89
+ # After validating the test release:
90
+ python -m twine upload dist/*
91
+ ```
92
+
93
+ ## Remote TD reads
94
+
95
+ Run the example against `data.current-robotics.work:443` (TLS by default):
96
+
97
+ ```bash
98
+ pip install 'current-data-py[remote]'
99
+ python -m current_data_py.examples.read_remote_td \
100
+ --name-prefix recording --topic /head/pose/command
101
+ ```
102
+
103
+ For a local plaintext service, pass `localhost:50051 --insecure`.
104
+ It opens the first matching TD and prints at most ten decoded messages.
105
+ Use `--start-timestamp` and `--end-timestamp` for an inclusive time range in
106
+ nanoseconds. The client obtains and reuses STS credentials automatically.
107
+
108
+
109
+ Install `current-data-py[remote]`. Import the optional API from
110
+ `current_data_py.remote`; basic schema imports do not load gRPC or the OSS SDK.
111
+
112
+ ```python
113
+ from contextlib import closing
114
+ from current_data_py import SCHEMA_TO_CLASS
115
+ from current_data_py.remote import DataClient, MetadataFilter
116
+
117
+ with DataClient() as client:
118
+ with closing(client.iter_data(MetadataFilter(name_prefix="recording"))) as items:
119
+ for metadata in items:
120
+ with client.open_td(metadata) as reader:
121
+ schemas = {
122
+ topic.name: topic.metadata["schema_name"]
123
+ for group in reader.summary().topics_infos
124
+ for topic in group.topic_metadatas
125
+ }
126
+ for message in reader.read_messages(topic_names=["/head/pose/command"]):
127
+ decoded = SCHEMA_TO_CLASS[schemas[message.topic_name]].FromString(message.data)
128
+ print(message.timestamp, decoded)
129
+ break
130
+ ```
131
+
132
+ `iter_data(filter=None, timeout=None)` yields partial `Metadata` objects with
133
+ only ID and storage populated. It consumes gRPC batches incrementally; close the
134
+ iterator when stopping early. A failed stream raises its gRPC error and is not
135
+ replayed. `DataClient()` defaults to `data.current-robotics.work:443` with TLS.
136
+ Use `DataClient(address="other-host:443")` to override the endpoint, or pass an
137
+ existing channel as `DataClient(channel)` (the channel takes precedence).
138
+ The context manager or `close()` closes only client-created channels; supplied
139
+ channels remain caller-owned. The read credential RPC has a 30-second
140
+ deadline; one client shares credentials across files and refreshes on demand
141
+ within five minutes of expiry. Only explicit token expiry triggers one refresh
142
+ and retry; other errors propagate. Credentials remain in memory.
143
+
144
+ `open_td(metadata)` supplies a regular TurboData Reader. Use its existing topic,
145
+ time-range and strategy options. The source performs HEAD once on opening and
146
+ Range reads with If-Match; changed objects and incomplete responses fail. Each
147
+ reading thread reuses its own HTTP connection pool. Finish all reads before
148
+ leaving the context, which releases those pools. If server endpoint or scope
149
+ changes, create a new DataClient. Objects must be finalized and directly readable.
150
+
151
+ Run `python /absolute/path/to/tests/check_remote.py` against the installed wheel
152
+ with the remote extra. It uses local gRPC and HTTP servers with the real Python
153
+ stub, OSS SDK and TD Reader; no cloud credentials are needed. Actual Go/OSS
154
+ production integration remains a separate deployment check.
@@ -0,0 +1,142 @@
1
+ # current-data-py
2
+
3
+ Current Data protobuf messages and schema metadata. Requires Python 3.9+.
4
+
5
+ ```bash
6
+ pip install current-data-py
7
+ ```
8
+
9
+ ```python
10
+ from current_data_py import SCHEMA_TO_CLASS, descriptor_set, topic_metadata
11
+ from current_data_py.schema import Pose
12
+
13
+ message = Pose()
14
+ message.position.y = 1.0
15
+ metadata = topic_metadata(Pose)
16
+ decoded = SCHEMA_TO_CLASS[metadata["schema_name"]].FromString(message.SerializeToString())
17
+ ```
18
+
19
+ TD examples write/read a Pose on `/head/pose/command`:
20
+
21
+ ```bash
22
+ python -m current_data_py.examples.write_td example.td
23
+ python -m current_data_py.examples.read_td example.td
24
+ ```
25
+
26
+ ## Layout
27
+
28
+ - `schema/`: message classes, schema registry and protobuf metadata helpers.
29
+ - `examples/`: runnable TD reading/writing and schema-listing examples.
30
+ - `remote/`: gRPC client/credential handling in `client.py`, OSS Range source in `source.py`.
31
+ - `tests/`: installed-package, distribution and remote integration checks.
32
+ - Root: package exports and build configuration.
33
+
34
+ `current_data_py.schema` and `current_data_py.remote` imports are preserved.
35
+ Metadata helpers also remain available from `current_data_py`; their module is
36
+ now `current_data_py.schema.message_metadata`. Run examples with
37
+ `python -m current_data_py.examples.read_td`, `write_td` or `list_schemas`.
38
+ Generated protobuf sources stay in the shared `proto_gen/python` tree and are
39
+ bundled under the private `_proto` namespace during packaging.
40
+
41
+ ## Development and releases
42
+
43
+ Packaging configuration lives in `current_data_py/`. Generated messages live
44
+ only in the repository's `proto_gen/python` (message schemas in `msg/`,
45
+ management RPC bindings in `management/`). Regenerate them using the existing
46
+ `proto/generate.sh` workflow after changing their proto definitions. Python RPC
47
+ generation uses `protoc` and `grpc_python_plugin` (tested with 3.21.12 and 1.51.1);
48
+ these are development tools and are not required when installing the package.
49
+ The build reads those files and adjusts their Python imports in the build
50
+ directory, placing them under `current_data_py._proto` in the wheel.
51
+ It does not modify or duplicate generated sources in the checkout.
52
+ The source distribution includes the original generated files so it can also
53
+ build without `protoc`. Installation requires neither the repository nor `protoc`.
54
+
55
+ ```bash
56
+ cd current_data_py # from the repository root
57
+ python -m pip install build twine
58
+ python -m build
59
+ python -m twine check dist/*
60
+ python tests/check_distribution.py
61
+ ```
62
+
63
+ Artifacts are written to `current_data_py/dist/`. The build adds the shared
64
+ protobuf inputs to the source archive without copying them into this directory.
65
+
66
+ For development, use a regular `pip install .` and run from outside the checkout;
67
+ reinstall after changes. Editable installs are not supported by this build step.
68
+
69
+ Install the wheel in a fresh environment and run
70
+ `python /absolute/path/to/current_data_py/tests/check_package.py` from outside
71
+ the repository. Use a clean `dist` for each release and increment the version
72
+ in `pyproject.toml`. Confirm the package name, license and supported Python
73
+ versions before publishing. No license has been selected yet.
74
+
75
+ ```bash
76
+ python -m twine upload --repository testpypi dist/*
77
+ # After validating the test release:
78
+ python -m twine upload dist/*
79
+ ```
80
+
81
+ ## Remote TD reads
82
+
83
+ Run the example against `data.current-robotics.work:443` (TLS by default):
84
+
85
+ ```bash
86
+ pip install 'current-data-py[remote]'
87
+ python -m current_data_py.examples.read_remote_td \
88
+ --name-prefix recording --topic /head/pose/command
89
+ ```
90
+
91
+ For a local plaintext service, pass `localhost:50051 --insecure`.
92
+ It opens the first matching TD and prints at most ten decoded messages.
93
+ Use `--start-timestamp` and `--end-timestamp` for an inclusive time range in
94
+ nanoseconds. The client obtains and reuses STS credentials automatically.
95
+
96
+
97
+ Install `current-data-py[remote]`. Import the optional API from
98
+ `current_data_py.remote`; basic schema imports do not load gRPC or the OSS SDK.
99
+
100
+ ```python
101
+ from contextlib import closing
102
+ from current_data_py import SCHEMA_TO_CLASS
103
+ from current_data_py.remote import DataClient, MetadataFilter
104
+
105
+ with DataClient() as client:
106
+ with closing(client.iter_data(MetadataFilter(name_prefix="recording"))) as items:
107
+ for metadata in items:
108
+ with client.open_td(metadata) as reader:
109
+ schemas = {
110
+ topic.name: topic.metadata["schema_name"]
111
+ for group in reader.summary().topics_infos
112
+ for topic in group.topic_metadatas
113
+ }
114
+ for message in reader.read_messages(topic_names=["/head/pose/command"]):
115
+ decoded = SCHEMA_TO_CLASS[schemas[message.topic_name]].FromString(message.data)
116
+ print(message.timestamp, decoded)
117
+ break
118
+ ```
119
+
120
+ `iter_data(filter=None, timeout=None)` yields partial `Metadata` objects with
121
+ only ID and storage populated. It consumes gRPC batches incrementally; close the
122
+ iterator when stopping early. A failed stream raises its gRPC error and is not
123
+ replayed. `DataClient()` defaults to `data.current-robotics.work:443` with TLS.
124
+ Use `DataClient(address="other-host:443")` to override the endpoint, or pass an
125
+ existing channel as `DataClient(channel)` (the channel takes precedence).
126
+ The context manager or `close()` closes only client-created channels; supplied
127
+ channels remain caller-owned. The read credential RPC has a 30-second
128
+ deadline; one client shares credentials across files and refreshes on demand
129
+ within five minutes of expiry. Only explicit token expiry triggers one refresh
130
+ and retry; other errors propagate. Credentials remain in memory.
131
+
132
+ `open_td(metadata)` supplies a regular TurboData Reader. Use its existing topic,
133
+ time-range and strategy options. The source performs HEAD once on opening and
134
+ Range reads with If-Match; changed objects and incomplete responses fail. Each
135
+ reading thread reuses its own HTTP connection pool. Finish all reads before
136
+ leaving the context, which releases those pools. If server endpoint or scope
137
+ changes, create a new DataClient. Objects must be finalized and directly readable.
138
+
139
+ Run `python /absolute/path/to/tests/check_remote.py` against the installed wheel
140
+ with the remote extra. It uses local gRPC and HTTP servers with the real Python
141
+ stub, OSS SDK and TD Reader; no cloud credentials are needed. Actual Go/OSS
142
+ production integration remains a separate deployment check.
@@ -1,6 +1,6 @@
1
1
  """Protobuf message schemas and metadata for Current Data."""
2
2
 
3
- from .message_metadata import descriptor_set, topic_metadata
3
+ from .schema.message_metadata import descriptor_set, topic_metadata
4
4
  from .schema import SCHEMA_TO_CLASS
5
5
 
6
6
  __all__ = ["SCHEMA_TO_CLASS", "descriptor_set", "topic_metadata"]
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: current-data-py
3
+ Version: 0.1.2
4
+ Summary: Current Data protobuf messages and schema metadata
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: protobuf>=3.20
8
+ Requires-Dist: turbodata==0.1.0
9
+ Provides-Extra: remote
10
+ Requires-Dist: grpcio>=1.51.1; extra == "remote"
11
+ Requires-Dist: alibabacloud-oss-v2<2,>=1.4.0; extra == "remote"
12
+
13
+ # current-data-py
14
+
15
+ Current Data protobuf messages and schema metadata. Requires Python 3.9+.
16
+
17
+ ```bash
18
+ pip install current-data-py
19
+ ```
20
+
21
+ ```python
22
+ from current_data_py import SCHEMA_TO_CLASS, descriptor_set, topic_metadata
23
+ from current_data_py.schema import Pose
24
+
25
+ message = Pose()
26
+ message.position.y = 1.0
27
+ metadata = topic_metadata(Pose)
28
+ decoded = SCHEMA_TO_CLASS[metadata["schema_name"]].FromString(message.SerializeToString())
29
+ ```
30
+
31
+ TD examples write/read a Pose on `/head/pose/command`:
32
+
33
+ ```bash
34
+ python -m current_data_py.examples.write_td example.td
35
+ python -m current_data_py.examples.read_td example.td
36
+ ```
37
+
38
+ ## Layout
39
+
40
+ - `schema/`: message classes, schema registry and protobuf metadata helpers.
41
+ - `examples/`: runnable TD reading/writing and schema-listing examples.
42
+ - `remote/`: gRPC client/credential handling in `client.py`, OSS Range source in `source.py`.
43
+ - `tests/`: installed-package, distribution and remote integration checks.
44
+ - Root: package exports and build configuration.
45
+
46
+ `current_data_py.schema` and `current_data_py.remote` imports are preserved.
47
+ Metadata helpers also remain available from `current_data_py`; their module is
48
+ now `current_data_py.schema.message_metadata`. Run examples with
49
+ `python -m current_data_py.examples.read_td`, `write_td` or `list_schemas`.
50
+ Generated protobuf sources stay in the shared `proto_gen/python` tree and are
51
+ bundled under the private `_proto` namespace during packaging.
52
+
53
+ ## Development and releases
54
+
55
+ Packaging configuration lives in `current_data_py/`. Generated messages live
56
+ only in the repository's `proto_gen/python` (message schemas in `msg/`,
57
+ management RPC bindings in `management/`). Regenerate them using the existing
58
+ `proto/generate.sh` workflow after changing their proto definitions. Python RPC
59
+ generation uses `protoc` and `grpc_python_plugin` (tested with 3.21.12 and 1.51.1);
60
+ these are development tools and are not required when installing the package.
61
+ The build reads those files and adjusts their Python imports in the build
62
+ directory, placing them under `current_data_py._proto` in the wheel.
63
+ It does not modify or duplicate generated sources in the checkout.
64
+ The source distribution includes the original generated files so it can also
65
+ build without `protoc`. Installation requires neither the repository nor `protoc`.
66
+
67
+ ```bash
68
+ cd current_data_py # from the repository root
69
+ python -m pip install build twine
70
+ python -m build
71
+ python -m twine check dist/*
72
+ python tests/check_distribution.py
73
+ ```
74
+
75
+ Artifacts are written to `current_data_py/dist/`. The build adds the shared
76
+ protobuf inputs to the source archive without copying them into this directory.
77
+
78
+ For development, use a regular `pip install .` and run from outside the checkout;
79
+ reinstall after changes. Editable installs are not supported by this build step.
80
+
81
+ Install the wheel in a fresh environment and run
82
+ `python /absolute/path/to/current_data_py/tests/check_package.py` from outside
83
+ the repository. Use a clean `dist` for each release and increment the version
84
+ in `pyproject.toml`. Confirm the package name, license and supported Python
85
+ versions before publishing. No license has been selected yet.
86
+
87
+ ```bash
88
+ python -m twine upload --repository testpypi dist/*
89
+ # After validating the test release:
90
+ python -m twine upload dist/*
91
+ ```
92
+
93
+ ## Remote TD reads
94
+
95
+ Run the example against `data.current-robotics.work:443` (TLS by default):
96
+
97
+ ```bash
98
+ pip install 'current-data-py[remote]'
99
+ python -m current_data_py.examples.read_remote_td \
100
+ --name-prefix recording --topic /head/pose/command
101
+ ```
102
+
103
+ For a local plaintext service, pass `localhost:50051 --insecure`.
104
+ It opens the first matching TD and prints at most ten decoded messages.
105
+ Use `--start-timestamp` and `--end-timestamp` for an inclusive time range in
106
+ nanoseconds. The client obtains and reuses STS credentials automatically.
107
+
108
+
109
+ Install `current-data-py[remote]`. Import the optional API from
110
+ `current_data_py.remote`; basic schema imports do not load gRPC or the OSS SDK.
111
+
112
+ ```python
113
+ from contextlib import closing
114
+ from current_data_py import SCHEMA_TO_CLASS
115
+ from current_data_py.remote import DataClient, MetadataFilter
116
+
117
+ with DataClient() as client:
118
+ with closing(client.iter_data(MetadataFilter(name_prefix="recording"))) as items:
119
+ for metadata in items:
120
+ with client.open_td(metadata) as reader:
121
+ schemas = {
122
+ topic.name: topic.metadata["schema_name"]
123
+ for group in reader.summary().topics_infos
124
+ for topic in group.topic_metadatas
125
+ }
126
+ for message in reader.read_messages(topic_names=["/head/pose/command"]):
127
+ decoded = SCHEMA_TO_CLASS[schemas[message.topic_name]].FromString(message.data)
128
+ print(message.timestamp, decoded)
129
+ break
130
+ ```
131
+
132
+ `iter_data(filter=None, timeout=None)` yields partial `Metadata` objects with
133
+ only ID and storage populated. It consumes gRPC batches incrementally; close the
134
+ iterator when stopping early. A failed stream raises its gRPC error and is not
135
+ replayed. `DataClient()` defaults to `data.current-robotics.work:443` with TLS.
136
+ Use `DataClient(address="other-host:443")` to override the endpoint, or pass an
137
+ existing channel as `DataClient(channel)` (the channel takes precedence).
138
+ The context manager or `close()` closes only client-created channels; supplied
139
+ channels remain caller-owned. The read credential RPC has a 30-second
140
+ deadline; one client shares credentials across files and refreshes on demand
141
+ within five minutes of expiry. Only explicit token expiry triggers one refresh
142
+ and retry; other errors propagate. Credentials remain in memory.
143
+
144
+ `open_td(metadata)` supplies a regular TurboData Reader. Use its existing topic,
145
+ time-range and strategy options. The source performs HEAD once on opening and
146
+ Range reads with If-Match; changed objects and incomplete responses fail. Each
147
+ reading thread reuses its own HTTP connection pool. Finish all reads before
148
+ leaving the context, which releases those pools. If server endpoint or scope
149
+ changes, create a new DataClient. Objects must be finalized and directly readable.
150
+
151
+ Run `python /absolute/path/to/tests/check_remote.py` against the installed wheel
152
+ with the remote extra. It uses local gRPC and HTTP servers with the real Python
153
+ stub, OSS SDK and TD Reader; no cloud credentials are needed. Actual Go/OSS
154
+ production integration remains a separate deployment check.
@@ -0,0 +1,33 @@
1
+ MANIFEST.in
2
+ README.md
3
+ __init__.py
4
+ pyproject.toml
5
+ setup.py
6
+ ./__init__.py
7
+ ./examples/__init__.py
8
+ ./examples/list_schemas.py
9
+ ./examples/read_remote_td.py
10
+ ./examples/read_td.py
11
+ ./examples/write_td.py
12
+ ./remote/__init__.py
13
+ ./remote/client.py
14
+ ./remote/source.py
15
+ ./schema/__init__.py
16
+ ./schema/message_metadata.py
17
+ current_data_py.egg-info/PKG-INFO
18
+ current_data_py.egg-info/SOURCES.txt
19
+ current_data_py.egg-info/dependency_links.txt
20
+ current_data_py.egg-info/requires.txt
21
+ current_data_py.egg-info/top_level.txt
22
+ examples/__init__.py
23
+ examples/list_schemas.py
24
+ examples/read_remote_td.py
25
+ examples/read_td.py
26
+ examples/write_td.py
27
+ remote/__init__.py
28
+ remote/client.py
29
+ remote/source.py
30
+ schema/__init__.py
31
+ schema/message_metadata.py
32
+ tests/check_package.py
33
+ tests/check_remote.py
@@ -0,0 +1,6 @@
1
+ protobuf>=3.20
2
+ turbodata==0.1.0
3
+
4
+ [remote]
5
+ grpcio>=1.51.1
6
+ alibabacloud-oss-v2<2,>=1.4.0
@@ -0,0 +1 @@
1
+ """Runnable examples for Current Data."""
@@ -0,0 +1,7 @@
1
+ from ..schema import SCHEMA_TO_CLASS
2
+
3
+
4
+ if __name__ == "__main__":
5
+ print("SCHEMA_TO_CLASS:")
6
+ for schema, msg_class in SCHEMA_TO_CLASS.items():
7
+ print(f" {schema}: {msg_class}")
@@ -0,0 +1,48 @@
1
+ """Read up to ten messages from the first matching remote TD file."""
2
+
3
+ import argparse
4
+ from contextlib import ExitStack, closing
5
+ from itertools import islice
6
+
7
+ from google.protobuf.text_format import MessageToString
8
+
9
+ from ..remote import DataClient, MetadataFilter
10
+ from ..schema import SCHEMA_TO_CLASS
11
+
12
+
13
+ def main() -> None:
14
+ parser = argparse.ArgumentParser(description=__doc__)
15
+ parser.add_argument("--name-prefix", default="", help="Filter recordings by name prefix")
16
+ parser.add_argument("--topic", default="/head/pose/command")
17
+ parser.add_argument("--start-timestamp", type=int, default=0, help="Inclusive start timestamp (ns)")
18
+ parser.add_argument("--end-timestamp", type=int, default=2**63 - 1, help="Inclusive end timestamp (ns)")
19
+ args = parser.parse_args()
20
+ if not 0 <= args.start_timestamp <= args.end_timestamp <= 2**63 - 1:
21
+ parser.error("timestamps must satisfy 0 <= start <= end <= 2**63 - 1")
22
+
23
+ with ExitStack() as stack:
24
+ client = stack.enter_context(DataClient())
25
+ with closing(client.iter_data(MetadataFilter(name_prefix=args.name_prefix), timeout=30)) as items:
26
+ metadata = next(items, None)
27
+ if metadata is None:
28
+ print("No matching data")
29
+ return
30
+
31
+ with client.open_td(metadata) as reader:
32
+ schemas = {
33
+ topic.name: topic.metadata["schema_name"]
34
+ for group in reader.summary().topics_infos
35
+ for topic in group.topic_metadatas
36
+ }
37
+ messages = reader.read_messages(
38
+ topic_names=[args.topic],
39
+ start_timestamp=args.start_timestamp,
40
+ end_timestamp=args.end_timestamp,
41
+ )
42
+ for message in islice(messages, 10):
43
+ decoded = SCHEMA_TO_CLASS[schemas[message.topic_name]].FromString(message.data)
44
+ print(metadata.data_id, message.timestamp, message.topic_name, MessageToString(decoded, as_one_line=True))
45
+
46
+
47
+ if __name__ == "__main__":
48
+ main()
@@ -3,7 +3,7 @@ from pathlib import Path
3
3
 
4
4
  from turbodata import FileReadSource, Reader
5
5
 
6
- from .schema import SCHEMA_TO_CLASS
6
+ from ..schema import SCHEMA_TO_CLASS
7
7
 
8
8
 
9
9
  def main() -> None:
@@ -4,8 +4,8 @@ from pathlib import Path
4
4
 
5
5
  from turbodata import Writer
6
6
 
7
- from .message_metadata import topic_metadata
8
- from .schema import Pose
7
+ from ..schema.message_metadata import topic_metadata
8
+ from ..schema import Pose
9
9
 
10
10
 
11
11
  TOPIC = "/head/pose/command"
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: management/metadata/metadata.proto
4
+ """Generated protocol buffer code."""
5
+ from google.protobuf.internal import builder as _builder
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ # @@protoc_insertion_point(imports)
10
+
11
+ _sym_db = _symbol_database.Default()
12
+
13
+
14
+ from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2
15
+ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
16
+
17
+
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"management/metadata/metadata.proto\x12\x16management.metadata.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xce\x03\n\x08Metadata\x12\x0f\n\x07\x64\x61ta_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x30\n\x07storage\x18\x03 \x01(\x0b\x32\x1f.management.metadata.v1.Storage\x12\x10\n\x08\x63hecksum\x18\x04 \x01(\t\x12.\n\ncreated_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x11\n\tdevice_id\x18\x07 \x01(\t\x12\x37\n\x0b\x64\x65vice_type\x18\x08 \x01(\x0e\x32\".management.metadata.v1.DeviceType\x12\x14\n\x0c\x64\x65vice_model\x18\t \x01(\t\x12\x38\n\x14recording_started_at\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\x08\x64uration\x18\x0b \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x36\n\x0e\x61\x63tive_sensors\x18\x0c \x03(\x0b\x32\x1e.management.metadata.v1.Sensor\"\xb7\x02\n\x0eMetadataFilter\x12\x13\n\x0bname_prefix\x18\x01 \x01(\t\x12\x38\n\x0c\x64\x65vice_types\x18\x02 \x03(\x0e\x32\".management.metadata.v1.DeviceType\x12:\n\x16recording_started_from\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x38\n\x14recording_started_to\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0cmin_duration\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12/\n\x0cmax_duration\x18\x06 \x01(\x0b\x32\x19.google.protobuf.Duration\"\x8d\x02\n\x06Sensor\x12\x30\n\x04type\x18\x01 \x01(\x0e\x32\".management.metadata.v1.SensorType\x12\x14\n\x0csample_count\x18\x02 \x01(\x04\x12\x14\n\x0c\x66requency_hz\x18\x03 \x01(\x01\x12\x12\n\x05width\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x13\n\x06height\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05model\x18\x06 \x01(\t\x12\x1c\n\x14\x63\x61libration_checksum\x18\x07 \x01(\t\x12!\n\x14\x64ropped_sample_count\x18\x08 \x01(\x04H\x02\x88\x01\x01\x42\x08\n\x06_widthB\t\n\x07_heightB\x17\n\x15_dropped_sample_count\"A\n\x07Storage\x12\x0e\n\x06\x62ucket\x18\x01 \x01(\t\x12\x12\n\nobject_key\x18\x02 \x01(\t\x12\x12\n\nsize_bytes\x18\x03 \x01(\x03*\x85\x01\n\nDeviceType\x12\x1b\n\x17\x44\x45VICE_TYPE_UNSPECIFIED\x10\x00\x12\x13\n\x0f\x44\x45VICE_TYPE_EGO\x10\x01\x12\x17\n\x13\x44\x45VICE_TYPE_EGO_EXO\x10\x02\x12\x17\n\x13\x44\x45VICE_TYPE_EGO_UMI\x10\x03\x12\x13\n\x0f\x44\x45VICE_TYPE_YAM\x10\x04*\xa6\x02\n\nSensorType\x12\x1b\n\x17SENSOR_TYPE_UNSPECIFIED\x10\x00\x12\x14\n\x10SENSOR_TYPE_CAM0\x10\x01\x12\x14\n\x10SENSOR_TYPE_CAM1\x10\x02\x12\x14\n\x10SENSOR_TYPE_CAM2\x10\x03\x12\x14\n\x10SENSOR_TYPE_CAM3\x10\x04\x12\x14\n\x10SENSOR_TYPE_IMU0\x10\x05\x12\x18\n\x14SENSOR_TYPE_IMU_LEFT\x10\x06\x12\x19\n\x15SENSOR_TYPE_IMU_RIGHT\x10\x07\x12\x1c\n\x18SENSOR_TYPE_GRIPPER_LEFT\x10\x08\x12\x1d\n\x19SENSOR_TYPE_GRIPPER_RIGHT\x10\t\x12\x1b\n\x17SENSOR_TYPE_EXOSKELETON\x10\nB*Z(proto_gen/management/metadata;metadatapbb\x06proto3')
19
+
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'management.metadata.metadata_pb2', globals())
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+
24
+ DESCRIPTOR._options = None
25
+ DESCRIPTOR._serialized_options = b'Z(proto_gen/management/metadata;metadatapb'
26
+ _DEVICETYPE._serialized_start=1246
27
+ _DEVICETYPE._serialized_end=1379
28
+ _SENSORTYPE._serialized_start=1382
29
+ _SENSORTYPE._serialized_end=1676
30
+ _METADATA._serialized_start=128
31
+ _METADATA._serialized_end=590
32
+ _METADATAFILTER._serialized_start=593
33
+ _METADATAFILTER._serialized_end=904
34
+ _SENSOR._serialized_start=907
35
+ _SENSOR._serialized_end=1176
36
+ _STORAGE._serialized_start=1178
37
+ _STORAGE._serialized_end=1243
38
+ # @@protoc_insertion_point(module_scope)