current-data-py 0.1.7__tar.gz → 0.1.10__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 (91) hide show
  1. {current_data_py-0.1.7 → current_data_py-0.1.10}/MANIFEST.in +5 -4
  2. current_data_py-0.1.10/PKG-INFO +370 -0
  3. current_data_py-0.1.10/README.md +356 -0
  4. current_data_py-0.1.10/__init__.py +17 -0
  5. current_data_py-0.1.10/current_data_py.egg-info/PKG-INFO +370 -0
  6. {current_data_py-0.1.7 → current_data_py-0.1.10}/current_data_py.egg-info/SOURCES.txt +3 -0
  7. {current_data_py-0.1.7 → current_data_py-0.1.10}/current_data_py.egg-info/requires.txt +4 -0
  8. current_data_py-0.1.10/decoding.py +187 -0
  9. {current_data_py-0.1.7 → current_data_py-0.1.10}/examples/__init__.py +1 -1
  10. {current_data_py-0.1.7 → current_data_py-0.1.10}/examples/list_schemas.py +7 -7
  11. {current_data_py-0.1.7 → current_data_py-0.1.10}/examples/read_remote_td.py +54 -54
  12. {current_data_py-0.1.7 → current_data_py-0.1.10}/examples/read_td.py +30 -30
  13. {current_data_py-0.1.7 → current_data_py-0.1.10}/examples/write_td.py +30 -30
  14. current_data_py-0.1.10/management.py +222 -0
  15. {current_data_py-0.1.7 → current_data_py-0.1.10}/oss.py +200 -182
  16. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/management/metadata/metadata_pb2.py +62 -62
  17. current_data_py-0.1.10/proto_gen/python/management/service/service_pb2.py +83 -0
  18. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/management/service/service_pb2_grpc.py +462 -330
  19. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/builtin_interfaces/duration_pb2.py +25 -25
  20. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/builtin_interfaces/time_pb2.py +25 -25
  21. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/custom_msgs/joint_current_pb2.py +26 -26
  22. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/custom_msgs/pose_rpy_pb2.py +26 -26
  23. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/custom_msgs/slam_quality_pb2.py +25 -25
  24. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/custom_msgs/sonic_frame_pb2.py +25 -25
  25. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/custom_msgs/target_quality_pb2.py +25 -25
  26. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/foxglove/compressed_audio_pb2.py +26 -26
  27. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/foxglove/compressed_video_pb2.py +26 -26
  28. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/point32_pb2.py +25 -25
  29. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/point_pb2.py +25 -25
  30. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/pose_pb2.py +27 -27
  31. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/pose_stamped_pb2.py +27 -27
  32. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/pose_with_covariance_pb2.py +26 -26
  33. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/pose_with_covariance_stamped_pb2.py +27 -27
  34. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/quaternion_pb2.py +25 -25
  35. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/transform_pb2.py +27 -27
  36. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/transform_stamped_pb2.py +27 -27
  37. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/twist_pb2.py +26 -26
  38. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/twist_stamped_pb2.py +27 -27
  39. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/twist_with_covariance_pb2.py +26 -26
  40. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/twist_with_covariance_stamped_pb2.py +27 -27
  41. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/vector3_pb2.py +25 -25
  42. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/wrench_pb2.py +26 -26
  43. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/geometry_msgs/wrench_stamped_pb2.py +27 -27
  44. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/nav_msgs/map_meta_data_pb2.py +27 -27
  45. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/nav_msgs/occupancy_grid_pb2.py +27 -27
  46. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/nav_msgs/odometry_pb2.py +28 -28
  47. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/nav_msgs/path_pb2.py +27 -27
  48. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/battery_state_pb2.py +32 -32
  49. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/camera_info_pb2.py +27 -27
  50. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/compressed_image_pb2.py +26 -26
  51. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/image_pb2.py +26 -26
  52. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/imu_pb2.py +28 -28
  53. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/joint_state_pb2.py +26 -26
  54. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/laser_scan_pb2.py +26 -26
  55. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/nav_sat_fix_pb2.py +29 -29
  56. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/nav_sat_status_pb2.py +27 -27
  57. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/point_cloud2_pb2.py +27 -27
  58. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/point_field_pb2.py +27 -27
  59. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/range_pb2.py +28 -28
  60. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/sensor_msgs/region_of_interest_pb2.py +25 -25
  61. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/std_msgs/bool_pb2.py +25 -25
  62. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/std_msgs/color_rgba_pb2.py +25 -25
  63. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/std_msgs/float32_pb2.py +25 -25
  64. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/std_msgs/float64_pb2.py +25 -25
  65. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/std_msgs/header_pb2.py +26 -26
  66. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/std_msgs/int32_pb2.py +25 -25
  67. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/std_msgs/string_pb2.py +25 -25
  68. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/std_msgs/uint32_pb2.py +25 -25
  69. {current_data_py-0.1.7 → current_data_py-0.1.10}/proto_gen/python/msg/tf2_msgs/tf_message_pb2.py +26 -26
  70. {current_data_py-0.1.7 → current_data_py-0.1.10}/pyproject.toml +24 -21
  71. {current_data_py-0.1.7 → current_data_py-0.1.10}/remote/__init__.py +7 -7
  72. {current_data_py-0.1.7 → current_data_py-0.1.10}/remote/client.py +97 -83
  73. {current_data_py-0.1.7 → current_data_py-0.1.10}/remote/source.py +98 -98
  74. {current_data_py-0.1.7 → current_data_py-0.1.10}/schema/__init__.py +107 -107
  75. {current_data_py-0.1.7 → current_data_py-0.1.10}/schema/message_metadata.py +30 -30
  76. {current_data_py-0.1.7 → current_data_py-0.1.10}/setup.py +60 -60
  77. current_data_py-0.1.10/tests/check_environment.py +79 -0
  78. current_data_py-0.1.10/tests/check_management.py +454 -0
  79. {current_data_py-0.1.7 → current_data_py-0.1.10}/tests/check_oss.py +424 -317
  80. {current_data_py-0.1.7 → current_data_py-0.1.10}/tests/check_package.py +43 -43
  81. {current_data_py-0.1.7 → current_data_py-0.1.10}/tests/check_remote.py +342 -289
  82. current_data_py-0.1.7/PKG-INFO +0 -136
  83. current_data_py-0.1.7/README.md +0 -125
  84. current_data_py-0.1.7/__init__.py +0 -8
  85. current_data_py-0.1.7/current_data_py.egg-info/PKG-INFO +0 -136
  86. current_data_py-0.1.7/management.py +0 -114
  87. current_data_py-0.1.7/proto_gen/python/management/service/service_pb2.py +0 -64
  88. current_data_py-0.1.7/tests/check_management.py +0 -253
  89. {current_data_py-0.1.7 → current_data_py-0.1.10}/current_data_py.egg-info/dependency_links.txt +0 -0
  90. {current_data_py-0.1.7 → current_data_py-0.1.10}/current_data_py.egg-info/top_level.txt +0 -0
  91. {current_data_py-0.1.7 → current_data_py-0.1.10}/setup.cfg +0 -0
@@ -1,4 +1,5 @@
1
- include tests/check_package.py
2
- include tests/check_remote.py
3
- include tests/check_management.py
4
- include tests/check_oss.py
1
+ include tests/check_package.py
2
+ include tests/check_environment.py
3
+ include tests/check_remote.py
4
+ include tests/check_management.py
5
+ include tests/check_oss.py
@@ -0,0 +1,370 @@
1
+ Metadata-Version: 2.4
2
+ Name: current-data-py
3
+ Version: 0.1.10
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
+ Requires-Dist: grpcio>=1.51.1
10
+ Requires-Dist: alibabacloud-oss-v2<2,>=1.4.0
11
+ Provides-Extra: decode
12
+ Requires-Dist: av>=12; extra == "decode"
13
+ Requires-Dist: pillow>=9; extra == "decode"
14
+
15
+ # current-data-py
16
+
17
+ ## Environment
18
+
19
+ Set `ENV=test` before importing the SDK to use the test service. `ENV=prod`,
20
+ an unset `ENV`, or an empty value selects production. Other values raise
21
+ `ValueError` at import time.
22
+
23
+ ```bash
24
+ ENV=test python -m current_data_py.examples.read_remote_td
25
+ ```
26
+
27
+ In Python, set the environment before the first SDK import:
28
+
29
+ ```python
30
+ import os
31
+ os.environ["ENV"] = "test"
32
+
33
+ from current_data_py.management import ManagementClient
34
+ from current_data_py.remote import DataClient
35
+
36
+ with ManagementClient() as management, DataClient() as data:
37
+ pass # Both clients use the test service over TLS.
38
+ ```
39
+
40
+ The environment initializes `current_data_py.DEFAULT_ADDRESS` once at import.
41
+ Changing `ENV` after import does not switch clients. An explicit `address=`
42
+ overrides the default; a caller-provided channel takes precedence over both.
43
+ Changing `current_data_py.DEFAULT_ADDRESS` still affects newly created clients.
44
+ OSS uploads and reads use credentials from the selected management service;
45
+ explicit bucket arguments remain unchanged.
46
+
47
+ ## Management
48
+
49
+ `ManagementClient` connects over TLS. Pass `address=` to configure the service,
50
+ or supply your own gRPC channel.
51
+
52
+ The examples below read deployment-specific values from environment variables.
53
+ Set `MANAGEMENT_ADDRESS` to your service address and `UPLOAD_DATA_TYPE` to a valid
54
+ integer enum value supplied by your deployment administrator. Set the bucket and
55
+ object-key variables to resources you are authorized to access. These variables
56
+ are read explicitly by the examples; they are not automatic SDK configuration.
57
+
58
+ ```python
59
+ import os
60
+
61
+ from current_data_py.management import ManagementClient, Metadata, MetadataFilter
62
+
63
+ with ManagementClient(address=os.environ["MANAGEMENT_ADDRESS"]) as client:
64
+ upload = client.get_upload_credentials(data_type=int(os.environ["UPLOAD_DATA_TYPE"]))
65
+ read = client.get_read_credentials(bucket=os.environ["READ_BUCKET"])
66
+
67
+ # Register an already uploaded file; replace the example file details.
68
+ record = client.register_data(Metadata(
69
+ name="recording",
70
+ data_type=int(os.environ["UPLOAD_DATA_TYPE"]),
71
+ storages=[{"bucket": os.environ["UPLOADED_BUCKET"], "object_key": os.environ["UPLOADED_OBJECT_KEY"]}],
72
+ file_info={"size_bytes": 1234, "checksum": "sha256:<file-hash>"},
73
+ ))
74
+ for item in client.stream_data_references(
75
+ MetadataFilter(name_prefix="recording"),
76
+ return_fields=["name", "data_type", "recording_info.task.name", "recording_info.recording_time"],
77
+ ):
78
+ print(item.id, item.name, item.data_type, item.storages, item.recording_info)
79
+ ```
80
+
81
+ `Metadata`, `MetadataFilter`, and responses are Protobuf objects exported by the
82
+ SDK. Registration only saves metadata; it does not upload files. Credential
83
+ calls return fresh credentials without caching. Calls accept `timeout=` and
84
+ `metadata=` for gRPC headers.
85
+
86
+ For uploads that distinguish raw and converted data, use V2 with both arguments:
87
+
88
+ ```python
89
+ with ManagementClient(address=os.environ["MANAGEMENT_ADDRESS"]) as client:
90
+ raw = client.get_upload_credentials_v2(data_type="YAM", data_kind="RAW")
91
+ converted = client.get_upload_credentials_v2(
92
+ data_type="YAM", data_kind="CONVERTED", use_internal_endpoint=True,
93
+ )
94
+ ```
95
+
96
+ V2 accepts `EGOSUITE`, `YAM`, and `CURRENT_V2` data types and `RAW` or `CONVERTED`
97
+ data kinds. Each argument also accepts its full enum name (`DATA_TYPE_YAM`,
98
+ `DATA_KIND_RAW`) or integer value. `DataKind` is exported from
99
+ `current_data_py.management`; data type constants are in `metadata_pb2`.
100
+ Unspecified or unknown enum values are rejected. `RAW` is not a V2 data type.
101
+ The server must have the selected environment/type/kind destination configured;
102
+ unfilled placeholders return `FAILED_PRECONDITION`. V2 requires a deployed
103
+ `GetUploadCredentialsV2` RPC and never falls back to the old RPC on failure.
104
+ The existing `get_upload_credentials()` API and its defaults remain unchanged.
105
+ V2 responses include the selected destination's `oss_endpoint` and `region`,
106
+ along with its bucket and prefix; raw and converted destinations may use different
107
+ OSS regions. The server derives the standard Alibaba Cloud endpoint from `region`:
108
+ `https://oss-<region>.aliyuncs.com` by default, or
109
+ `https://oss-<region>-internal.aliyuncs.com` with `use_internal_endpoint=True`.
110
+ Use the internal endpoint from Alibaba Cloud resources in the same region.
111
+ See the [Alibaba Cloud endpoint reference](https://www.alibabacloud.com/help/en/oss/user-guide/regions-and-endpoints).
112
+ `OSSClient` accepts the same option for V2 uploads and retains it when refreshing
113
+ credentials. It uses the returned endpoint and region for connections and signing.
114
+ An explicit `region=` must match the returned region. If the endpoint or
115
+ region changes during credential refresh, create a new `OSSClient`.
116
+
117
+ For reads in the bucket's own region, use the new read V2 RPC:
118
+
119
+ ```python
120
+ with ManagementClient(address=os.environ["MANAGEMENT_ADDRESS"]) as client:
121
+ read = client.get_read_credentials_v2(
122
+ bucket=os.environ["READ_BUCKET"], use_internal_endpoint=False,
123
+ )
124
+ ```
125
+
126
+ The bucket is required and must appear in the service's environment-specific
127
+ bucket-to-region map, shared with V2 uploads. Reads grant whole-bucket `GetObject`
128
+ access bounded by the read RAM role. Public networking is the default; set
129
+ `use_internal_endpoint=True` for internal networking. Unconfigured buckets return
130
+ `FAILED_PRECONDITION`; empty or malformed buckets return `INVALID_ARGUMENT`.
131
+ The existing `get_read_credentials()` API keeps its configured default endpoint,
132
+ region and scope. V2 calls never fall back to it on failure.
133
+
134
+ ### Multi-cloud credentials (V3)
135
+
136
+ Use V3 to explicitly choose OSS or native TOS. `StorageProvider` and
137
+ `StorageCredentials` are exported from `current_data_py.management`.
138
+
139
+ ```python
140
+ from current_data_py.management import ManagementClient
141
+
142
+ with ManagementClient() as client:
143
+ upload = client.get_upload_credentials_v3(
144
+ provider="TOS", data_type="YAM", data_kind="RAW",
145
+ use_internal_endpoint=False,
146
+ )
147
+ read = client.get_read_credentials_v3(
148
+ provider="TOS", bucket=upload.bucket,
149
+ use_internal_endpoint=False,
150
+ )
151
+ print(upload.provider, upload.bucket, upload.endpoint, upload.region)
152
+ ```
153
+
154
+ `provider` is required and accepts `OSS`/`TOS`, full enum names such as
155
+ `STORAGE_PROVIDER_TOS`, or enum integer values. Unspecified/unknown providers
156
+ are rejected. Uploads require the same explicit type/kind as V2; reads require
157
+ an explicitly configured bucket on the selected provider. OSS V3 uses the same
158
+ routes and roles as OSS V2. TOS configuration and IAM preparation are described
159
+ in the [service deployment guide](../management_service/README.md#tos-preparation-for-v3).
160
+
161
+ Both calls return `provider`, `endpoint`, `region`, `bucket`, `object_prefix`,
162
+ `access_key_id`, `access_key_secret`, `security_token`, and `expires_at`.
163
+ `object_prefix` is empty for whole-bucket reads. Use `endpoint` instead of V2's
164
+ `oss_endpoint`. TOS public endpoints use `tos-<region>.volces.com`; internal
165
+ endpoints use `tos-<region>.ivolces.com`. Internal networking requires access to
166
+ the destination cloud and region's private network.
167
+
168
+ V3 calls accept `timeout` and `metadata`, do not cache credentials, and never
169
+ retry or fall back to earlier RPC versions. Old servers return `UNIMPLEMENTED`;
170
+ unconfigured destinations return `FAILED_PRECONDITION`. A response whose
171
+ provider differs from the request raises `ValueError`.
172
+
173
+ These methods only fetch credentials. Pass TOS credentials to a native TOS
174
+ client and refresh them before expiration. `OSSClient`, `DataClient`, metadata
175
+ registration and signed URLs have not been extended to TOS by this change.
176
+
177
+ ## Remote TD reads
178
+
179
+ ### Payload decoding
180
+
181
+ > [!IMPORTANT]
182
+ > **Video decoding requires PyAV, Pillow and the FFmpeg native libraries used by
183
+ > PyAV.** `open_td()` enables decoding by default, but a base `current-data-py`
184
+ > installation does not install the video dependencies. Install the `[decode]`
185
+ > extra in every environment that decodes video, including DataLoader workers.
186
+
187
+ ```bash
188
+ python -m pip install --only-binary=av,pillow 'current-data-py[decode]'
189
+ ```
190
+
191
+ - **Prebuilt wheels:** PyAV wheels bundle FFmpeg libraries on supported platforms;
192
+ no separate FFmpeg system installation is normally needed. The command above
193
+ fails if compatible PyAV/Pillow wheels are unavailable instead of silently
194
+ compiling them. Wheel availability depends on Python, OS and architecture.
195
+ - **Source builds:** install a compiler, Python development headers, `pkg-config`
196
+ and compatible FFmpeg development libraries: `libavcodec`, `libavformat`,
197
+ `libavutil`, `libavdevice`, `libavfilter`, `libswscale` and `libswresample`.
198
+ Runtime shared libraries must also remain available in the deployed environment.
199
+ Follow the requirements for your chosen [PyAV version](https://pyav.basswood.io/docs/stable/overview/installation.html)
200
+ and [Pillow build](https://pillow.readthedocs.io/en/stable/installation/building-from-source.html).
201
+ - **The `ffmpeg` executable alone is insufficient:** this SDK calls PyAV's native
202
+ library bindings, not a command-line subprocess. Decoding uses the CPU and does
203
+ not require CUDA or a GPU.
204
+ - **Protobuf-only decoding and raw reads** (`enable_decode=False`) do not require
205
+ PyAV, Pillow or FFmpeg for decoding.
206
+
207
+ Check the video dependencies in the environment that will run the reader:
208
+
209
+ ```bash
210
+ python -c "import av; from PIL import Image; av.CodecContext.create('h264', 'r'); print(av.library_versions)"
211
+ ```
212
+
213
+ Decoding applies to both sequential reads and time sampling; it does not depend
214
+ on a robot dataset format.
215
+
216
+ ```python
217
+ # Read all messages in an inclusive time range, without constructing sample queries.
218
+ with client.open_td(reference, bucket=bucket) as reader:
219
+ messages = reader.read_messages(
220
+ topic_names=topics,
221
+ start_timestamp=start_ns,
222
+ end_timestamp=end_ns,
223
+ )
224
+ try:
225
+ for result in messages:
226
+ print(result.topic_name, result.timestamp, type(result.value))
227
+ finally:
228
+ messages.close() # Also release iterator state when stopping early.
229
+ ```
230
+
231
+ Sequential results are `DecodedMessage(topic_name, timestamp, value)`. Reads are
232
+ lazy: all selected topics share one raw read iterator, with a separate video decoder
233
+ per topic. Results are yielded as decoding completes; delayed video frames can
234
+ arrive after newer messages from other topics. Use each result's timestamp for alignment.
235
+ GOP prefix frames are consumed for decoding but excluded from returned
236
+ results outside the requested time bounds. Reverse-order decoded reads are not
237
+ supported; use `raw` for reverse encoded reads.
238
+
239
+ To request particular timestamps instead:
240
+
241
+ ```python
242
+ from turbodata import SampleQuery
243
+
244
+ # reference, bucket, topic and timestamps_ns come from your selected recording.
245
+ with client.open_td(reference, bucket=bucket) as reader:
246
+ samples_by_topic = reader.sample([SampleQuery(topic, timestamps_ns)])
247
+ for sample in samples_by_topic[0]:
248
+ if sample.found:
249
+ print(sample.timestamp, type(sample.value))
250
+ ```
251
+
252
+ `value` is a Protobuf message, or an RGB PIL image
253
+ for H.264 video. Missing samples have `found=False` and `value=None`. Timestamps are
254
+ actual floor-match times, not necessarily the requested times. Repeated video
255
+ samples may share the same image object; copy it before modifying it in place.
256
+ Decoding errors propagate; no normalization, resizing or alignment tolerance is
257
+ applied. Only schemas registered in the SDK are decoded. An unregistered schema
258
+ raises `KeyError` with the schema name, even if the TD metadata
259
+ includes a descriptor. Unsupported video codecs also raise errors.
260
+
261
+ Decoding is enabled by default. Set `enable_decode=False` to return the original
262
+ TurboData Reader when your code needs encoded payloads in `.data`.
263
+ The decoded reader exposes `summary()`, `read_messages()`, `sample()` and `raw`;
264
+ use `raw` for encoded reads and other low-level APIs. Video sampling automatically requests
265
+ GOP dependencies. Keep all reads inside the `open_td()` context.
266
+
267
+ For a local Reader, use `current_data_py.decoding.DecodedReader(reader)`. The same
268
+ module exports `decode_messages(payloads, schema)` and `decode_video(results)` for
269
+ already-read payloads. Supply a complete ordered row from
270
+ `Reader.sample(video_decodable=True)` to `decode_video`; decoder state is local
271
+ to each call.
272
+
273
+ ### Storage and credentials
274
+
275
+ `DataClient.open_td()` accepts an optional `bucket` argument. Without it, reads
276
+ use the management service's `OSS_READ_BUCKET` and `OSS_READ_PREFIX` defaults.
277
+ With it, the SDK uses `GetReadCredentialsV2` for whole-bucket credentials in the
278
+ bucket's region, limited by the server's RAM role, and selects the first matching
279
+ storage in the reference. An explicit bucket does not inherit the default prefix.
280
+ Set `use_internal_endpoint=True` with an explicit bucket to use internal networking.
281
+ Credentials are cached separately for each `(bucket, use_internal_endpoint)` pair,
282
+ apart from the legacy default scope, and refreshed automatically.
283
+
284
+ ```python
285
+ import os
286
+
287
+ from current_data_py.remote import DataClient
288
+
289
+ with DataClient(address=os.environ["MANAGEMENT_ADDRESS"]) as client:
290
+ for reference in client.iter_data():
291
+ # Use the service's default bucket and prefix.
292
+ with client.open_td(reference) as reader:
293
+ print(reader.summary())
294
+
295
+ # Request read access to the selected bucket.
296
+ with client.open_td(reference, bucket=os.environ["READ_BUCKET"]) as reader:
297
+ print(reader.summary())
298
+ ```
299
+
300
+ The explicit bucket must contain a storage listed in the reference and have a
301
+ configured region on the server. Deploy `GetReadCredentialsV2` before upgrading
302
+ clients that use explicit buckets; older servers return `UNIMPLEMENTED` and the
303
+ SDK does not fall back to a potentially incorrect legacy endpoint.
304
+
305
+ ## OSS
306
+
307
+ ```python
308
+ import os
309
+
310
+ from current_data_py.management import ManagementClient
311
+ from current_data_py.oss import OSSClient
312
+
313
+ with ManagementClient(address=os.environ["MANAGEMENT_ADDRESS"]) as management:
314
+ with OSSClient(management, permission="read", bucket=os.environ["READ_BUCKET"]) as source:
315
+ source.download_file(os.environ["SOURCE_OBJECT_KEY"], "/tmp/input.h5")
316
+
317
+ # Convert the input into /tmp/output.td before uploading.
318
+ with OSSClient(management, permission="upload", data_type=int(os.environ["UPLOAD_DATA_TYPE"]),
319
+ data_kind="CONVERTED") as destination:
320
+ key = destination.object_prefix + "recording/output.td"
321
+ destination.upload_file(key, "/tmp/output.td")
322
+ print(destination.bucket, key) # Use these values when registering metadata.
323
+ ```
324
+
325
+ - Read access uses V2 and covers the requested bucket, subject to server permissions.
326
+ The server chooses the upload bucket and prefix based on the requested data type
327
+ and kind. Supplying `data_kind` selects V2 and requires `data_type`; omit
328
+ `data_kind` to retain the legacy upload API. Read clients reject both arguments.
329
+ - Reads and V2 uploads use the public endpoint by default. Set `use_internal_endpoint=True`
330
+ on `OSSClient` to select internal networking. Legacy uploads reject this option.
331
+ - Credentials refresh automatically. Expired tokens trigger one refresh and retry.
332
+ - Uploads reject overwrites by default; set `forbid_overwrite=False` to replace.
333
+ Downloads replace the local file only on success; its parent directory must exist.
334
+ - Uploads use a single PutObject request ([maximum 5 GiB](https://www.alibabacloud.com/help/en/oss/developer-reference/upload-files-using-oss-sdk-for-python-v2/)); multipart upload is not supported.
335
+ - Supply `region=` for legacy custom upload endpoints; V2 returns its own region.
336
+ Deploy the V2 credential APIs and configure bucket regions before using reads
337
+ or the upload `data_kind` option.
338
+
339
+ ## 打包
340
+
341
+ ```bash
342
+ cd current_data_py # 从仓库根目录执行
343
+ # 发布新版本前,更新 pyproject.toml 中的 version
344
+ python -m pip install build twine
345
+ rm -rf build dist
346
+ python -m build
347
+ ```
348
+
349
+ ## 测试
350
+
351
+ ```bash
352
+ python -m twine check dist/*
353
+ python tests/check_distribution.py
354
+ python -m pip install --force-reinstall dist/*.whl
355
+ python -I tests/check_package.py
356
+ python -I tests/check_environment.py
357
+ python -I tests/check_management.py
358
+ python -I tests/check_remote.py
359
+ python -I tests/check_oss.py
360
+ ```
361
+
362
+ ## 推送
363
+
364
+ ```bash
365
+ # TestPyPI
366
+ python -m twine upload --repository testpypi dist/*
367
+
368
+ # PyPI
369
+ python -m twine upload dist/*
370
+ ```