pyroboframes 2.6.2__tar.gz → 2.6.3__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 (86) hide show
  1. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/Cargo.lock +19 -48
  2. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/Cargo.toml +1 -1
  3. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/PKG-INFO +1 -1
  4. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-py/Cargo.toml +2 -2
  5. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-py/src/lib.rs +48 -35
  6. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/LICENSE +0 -0
  7. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/README.md +0 -0
  8. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/Cargo.toml +0 -0
  9. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/adaptive.rs +0 -0
  10. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/anomaly.rs +0 -0
  11. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/cache.rs +0 -0
  12. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/calibration.rs +0 -0
  13. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/data.rs +0 -0
  14. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/dataset.rs +0 -0
  15. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/decisions.rs +0 -0
  16. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/decode.rs +0 -0
  17. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/depth.rs +0 -0
  18. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/distributed.rs +0 -0
  19. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/ensemble.rs +0 -0
  20. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/episodes.rs +0 -0
  21. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/feedback.rs +0 -0
  22. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/info.rs +0 -0
  23. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/intelligence.rs +0 -0
  24. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/lib.rs +0 -0
  25. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/loader.rs +0 -0
  26. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/mcap.rs +0 -0
  27. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/mcp.rs +0 -0
  28. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/metrics.rs +0 -0
  29. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/models.rs +0 -0
  30. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/pipeline.rs +0 -0
  31. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/quality.rs +0 -0
  32. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/resilience.rs +0 -0
  33. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/rng.rs +0 -0
  34. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/ros2.rs +0 -0
  35. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/rosbag.rs +0 -0
  36. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/sampler.rs +0 -0
  37. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/split.rs +0 -0
  38. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/stats.rs +0 -0
  39. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/streaming.rs +0 -0
  40. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/validate.rs +0 -0
  41. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/videotoolbox_native.rs +0 -0
  42. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/src/window.rs +0 -0
  43. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/tests/cross_project_integration_test.rs +0 -0
  44. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/tests/integration_test.rs +0 -0
  45. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/tests/phase4_integration_test.rs +0 -0
  46. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/tests/phase5_integration_test.rs +0 -0
  47. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/tests/phase6_integration_test.rs +0 -0
  48. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/tests/phase7_integration_test.rs +0 -0
  49. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/crates/pyroboframes-core/tests/phase8_integration_test.rs +0 -0
  50. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/pyproject.toml +0 -0
  51. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/__init__.py +0 -0
  52. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/_format_registry.py +0 -0
  53. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/augmentation.py +0 -0
  54. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/backend.py +0 -0
  55. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/compression.py +0 -0
  56. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/cvcuda_transforms.py +0 -0
  57. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/dataframe.py +0 -0
  58. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/dataloader.py +0 -0
  59. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/dataset_loaders.py +0 -0
  60. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/depth_io.py +0 -0
  61. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/distributed.py +0 -0
  62. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/episode_cache.py +0 -0
  63. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/error_messages.py +0 -0
  64. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/filtering.py +0 -0
  65. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/gpu_acceleration.py +0 -0
  66. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/hdf5.py +0 -0
  67. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/hub.py +0 -0
  68. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/lazy_parquet.py +0 -0
  69. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/lerobot.py +0 -0
  70. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/masking.py +0 -0
  71. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/netcdf.py +0 -0
  72. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/occupancy_3d.py +0 -0
  73. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/parquet_writer.py +0 -0
  74. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/proprioceptive_loader.py +0 -0
  75. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/quality.py +0 -0
  76. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/rlds.py +0 -0
  77. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/security.py +0 -0
  78. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/sensor_fusion.py +0 -0
  79. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/streaming.py +0 -0
  80. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/tensorflow_support.py +0 -0
  81. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/transforms.py +0 -0
  82. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/unified_outputs.py +0 -0
  83. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/validation.py +0 -0
  84. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/versioning.py +0 -0
  85. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/video_sync.py +0 -0
  86. {pyroboframes-2.6.2 → pyroboframes-2.6.3}/python/pyroboframes/warnings.py +0 -0
@@ -821,15 +821,6 @@ dependencies = [
821
821
  "hashbrown 0.17.1",
822
822
  ]
823
823
 
824
- [[package]]
825
- name = "indoc"
826
- version = "2.0.7"
827
- source = "registry+https://github.com/rust-lang/crates.io-index"
828
- checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
829
- dependencies = [
830
- "rustversion",
831
- ]
832
-
833
824
  [[package]]
834
825
  name = "itertools"
835
826
  version = "0.14.0"
@@ -1049,15 +1040,6 @@ dependencies = [
1049
1040
  "libc",
1050
1041
  ]
1051
1042
 
1052
- [[package]]
1053
- name = "memoffset"
1054
- version = "0.9.1"
1055
- source = "registry+https://github.com/rust-lang/crates.io-index"
1056
- checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
1057
- dependencies = [
1058
- "autocfg",
1059
- ]
1060
-
1061
1043
  [[package]]
1062
1044
  name = "miniz_oxide"
1063
1045
  version = "0.8.9"
@@ -1169,9 +1151,9 @@ dependencies = [
1169
1151
 
1170
1152
  [[package]]
1171
1153
  name = "numpy"
1172
- version = "0.22.1"
1154
+ version = "0.29.0"
1173
1155
  source = "registry+https://github.com/rust-lang/crates.io-index"
1174
- checksum = "edb929bc0da91a4d85ed6c0a84deaa53d411abfb387fc271124f91bf6b89f14e"
1156
+ checksum = "6a5b15d63a5ff39e378daed0e1340d3a5964703ea9712eb09a0dc66fade996f4"
1175
1157
  dependencies = [
1176
1158
  "libc",
1177
1159
  "ndarray",
@@ -1179,6 +1161,7 @@ dependencies = [
1179
1161
  "num-integer",
1180
1162
  "num-traits",
1181
1163
  "pyo3",
1164
+ "pyo3-build-config",
1182
1165
  "rustc-hash",
1183
1166
  ]
1184
1167
 
@@ -1347,37 +1330,32 @@ dependencies = [
1347
1330
 
1348
1331
  [[package]]
1349
1332
  name = "pyo3"
1350
- version = "0.22.6"
1333
+ version = "0.29.3"
1351
1334
  source = "registry+https://github.com/rust-lang/crates.io-index"
1352
- checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884"
1335
+ checksum = "700d18fa267b73b9b521fd7e13580e2f446916f176cacee1ab63fcc8191f1655"
1353
1336
  dependencies = [
1354
- "cfg-if",
1355
- "indoc",
1356
1337
  "libc",
1357
- "memoffset",
1358
1338
  "once_cell",
1359
1339
  "portable-atomic",
1360
1340
  "pyo3-build-config",
1361
1341
  "pyo3-ffi",
1362
1342
  "pyo3-macros",
1363
- "unindent",
1364
1343
  ]
1365
1344
 
1366
1345
  [[package]]
1367
1346
  name = "pyo3-build-config"
1368
- version = "0.22.6"
1347
+ version = "0.29.3"
1369
1348
  source = "registry+https://github.com/rust-lang/crates.io-index"
1370
- checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38"
1349
+ checksum = "7b3fc0c4d08f6bb10e71fe39dfb9e2f59c6eb6854e22ec8092f50c69a4499adb"
1371
1350
  dependencies = [
1372
- "once_cell",
1373
1351
  "target-lexicon",
1374
1352
  ]
1375
1353
 
1376
1354
  [[package]]
1377
1355
  name = "pyo3-ffi"
1378
- version = "0.22.6"
1356
+ version = "0.29.3"
1379
1357
  source = "registry+https://github.com/rust-lang/crates.io-index"
1380
- checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636"
1358
+ checksum = "dfc0b8e19df29aad7086cf977bb0c2a2f143e30567eb113e9cf72b62ca698330"
1381
1359
  dependencies = [
1382
1360
  "libc",
1383
1361
  "pyo3-build-config",
@@ -1385,9 +1363,9 @@ dependencies = [
1385
1363
 
1386
1364
  [[package]]
1387
1365
  name = "pyo3-macros"
1388
- version = "0.22.6"
1366
+ version = "0.29.3"
1389
1367
  source = "registry+https://github.com/rust-lang/crates.io-index"
1390
- checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453"
1368
+ checksum = "6100e8a4b5eba53afaa5ed078364851a0b2499c553a44c31026b929049b49dc6"
1391
1369
  dependencies = [
1392
1370
  "proc-macro2",
1393
1371
  "pyo3-macros-backend",
@@ -1397,20 +1375,19 @@ dependencies = [
1397
1375
 
1398
1376
  [[package]]
1399
1377
  name = "pyo3-macros-backend"
1400
- version = "0.22.6"
1378
+ version = "0.29.3"
1401
1379
  source = "registry+https://github.com/rust-lang/crates.io-index"
1402
- checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe"
1380
+ checksum = "6143877a16e82b5a727b7127ff4cd86858a24a28d745d72f43e6f227c7b1bdb3"
1403
1381
  dependencies = [
1404
1382
  "heck",
1405
1383
  "proc-macro2",
1406
- "pyo3-build-config",
1407
1384
  "quote",
1408
1385
  "syn 2.0.119",
1409
1386
  ]
1410
1387
 
1411
1388
  [[package]]
1412
1389
  name = "pyroboframes-core"
1413
- version = "2.6.2"
1390
+ version = "2.6.3"
1414
1391
  dependencies = [
1415
1392
  "apple-cf",
1416
1393
  "arrow",
@@ -1435,7 +1412,7 @@ dependencies = [
1435
1412
 
1436
1413
  [[package]]
1437
1414
  name = "pyroboframes-py"
1438
- version = "2.6.2"
1415
+ version = "2.6.3"
1439
1416
  dependencies = [
1440
1417
  "numpy",
1441
1418
  "pyo3",
@@ -1523,9 +1500,9 @@ dependencies = [
1523
1500
 
1524
1501
  [[package]]
1525
1502
  name = "rustc-hash"
1526
- version = "1.1.0"
1503
+ version = "2.1.3"
1527
1504
  source = "registry+https://github.com/rust-lang/crates.io-index"
1528
- checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
1505
+ checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
1529
1506
 
1530
1507
  [[package]]
1531
1508
  name = "rustc_version"
@@ -1698,9 +1675,9 @@ dependencies = [
1698
1675
 
1699
1676
  [[package]]
1700
1677
  name = "target-lexicon"
1701
- version = "0.12.16"
1678
+ version = "0.13.5"
1702
1679
  source = "registry+https://github.com/rust-lang/crates.io-index"
1703
- checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
1680
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
1704
1681
 
1705
1682
  [[package]]
1706
1683
  name = "tempfile"
@@ -1776,12 +1753,6 @@ version = "1.0.24"
1776
1753
  source = "registry+https://github.com/rust-lang/crates.io-index"
1777
1754
  checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
1778
1755
 
1779
- [[package]]
1780
- name = "unindent"
1781
- version = "0.2.4"
1782
- source = "registry+https://github.com/rust-lang/crates.io-index"
1783
- checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
1784
-
1785
1756
  [[package]]
1786
1757
  name = "vcpkg"
1787
1758
  version = "0.2.15"
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/pyroboframes-core", "crates/pyroboframes-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "2.6.2"
6
+ version = "2.6.3"
7
7
  edition = "2021"
8
8
  rust-version = "1.78"
9
9
  license = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyroboframes
3
- Version: 2.6.2
3
+ Version: 2.6.3
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Intended Audience :: Science/Research
@@ -14,8 +14,8 @@ crate-type = ["cdylib"]
14
14
 
15
15
  [dependencies]
16
16
  pyroboframes-core = { path = "../pyroboframes-core" }
17
- pyo3 = { version = "0.22", features = ["abi3-py310"] }
18
- numpy = "0.22"
17
+ pyo3 = { version = "0.29", features = ["abi3-py310"] }
18
+ numpy = "0.29"
19
19
 
20
20
  [features]
21
21
  # Enabled by maturin when building the wheel (see pyproject.toml). Left off for plain
@@ -13,6 +13,7 @@
13
13
  use std::collections::BTreeMap;
14
14
  use std::path::{Path, PathBuf};
15
15
  use std::sync::Arc;
16
+ use std::sync::Mutex;
16
17
 
17
18
  use numpy::ndarray::{Array1, Array2, Array3, Array4, ArrayD, IxDyn};
18
19
  use numpy::IntoPyArray;
@@ -204,9 +205,9 @@ impl RoboFrameDataset {
204
205
  let Some(stats) = self.dataset.stats().map_err(core_err)? else {
205
206
  return Ok(None);
206
207
  };
207
- let out = PyDict::new_bound(py);
208
+ let out = PyDict::new(py);
208
209
  for (name, fs) in &stats.features {
209
- let d = PyDict::new_bound(py);
210
+ let d = PyDict::new(py);
210
211
  d.set_item("mean", fs.mean.clone())?;
211
212
  d.set_item("std", fs.std.clone())?;
212
213
  d.set_item("min", fs.min.clone())?;
@@ -229,9 +230,9 @@ impl RoboFrameDataset {
229
230
  /// index to `loader(episodes=[i])` to load a single episode.
230
231
  fn episodes(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
231
232
  let index = self.dataset.episodes().map_err(core_err)?;
232
- let out = pyo3::types::PyList::empty_bound(py);
233
+ let out = pyo3::types::PyList::empty(py);
233
234
  for ep in index.episodes() {
234
- let d = PyDict::new_bound(py);
235
+ let d = PyDict::new(py);
235
236
  d.set_item("episode_index", ep.episode_index)?;
236
237
  d.set_item("length", ep.length)?;
237
238
  d.set_item("from_index", ep.from_index)?;
@@ -432,7 +433,7 @@ impl RoboFrameDataset {
432
433
  (None, FrameCache::new(1))
433
434
  } else {
434
435
  let cap = cache_size.unwrap_or_else(|| (batch_size * cameras.len() * 8).max(256));
435
- (Some(new_frame_decoder()?), FrameCache::new(cap))
436
+ (Some(Mutex::new(new_frame_decoder()?)), FrameCache::new(cap))
436
437
  };
437
438
 
438
439
  let loader = Loader {
@@ -474,7 +475,7 @@ struct Loader {
474
475
  window: Option<WindowSpec>,
475
476
  /// Camera streams to decode into frame arrays (empty = tabular only).
476
477
  cameras: Vec<String>,
477
- frame_decoder: Option<Box<dyn Decoder + Send>>,
478
+ frame_decoder: Option<std::sync::Mutex<Box<dyn Decoder + Send>>>,
478
479
  frame_cache: FrameCache,
479
480
  /// "numpy" | "mlx" | "torch"
480
481
  output: String,
@@ -547,7 +548,13 @@ impl Loader {
547
548
  let dict = batch.bind(py);
548
549
  match self.window.clone() {
549
550
  None => {
550
- let decoder = self.frame_decoder.as_deref_mut().expect("decoder set");
551
+ let mut decoder_guard = self
552
+ .frame_decoder
553
+ .as_ref()
554
+ .expect("decoder set")
555
+ .lock()
556
+ .expect("decoder lock poisoned");
557
+ let decoder: &mut dyn Decoder = &mut **decoder_guard;
551
558
  // camera -> decoded frames in batch order. `Frame` clones are cheap (the
552
559
  // pixel buffer is `Arc`-backed), so collecting them all before writing out
553
560
  // costs no extra pixel copies over the previous single-pass version.
@@ -570,13 +577,13 @@ impl Loader {
570
577
  // gap referred to: no shared batch buffer exists for frames to be copied
571
578
  // into at all, so there is nothing left to copy here.
572
579
  for (cam, frames) in by_camera {
573
- let frame_list = PyList::empty_bound(py);
580
+ let frame_list = PyList::empty(py);
574
581
  for frame in &frames {
575
582
  let (w, h) = (frame.width as usize, frame.height as usize);
576
583
  let data = frame.to_rgb24_bytes();
577
584
  let arr = Array3::from_shape_vec((h, w, 3), data)
578
585
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
579
- frame_list.append(arr.into_pyarray_bound(py))?;
586
+ frame_list.append(arr.into_pyarray(py))?;
580
587
  }
581
588
  dict.set_item(cam, frame_list)?;
582
589
  }
@@ -605,12 +612,18 @@ impl Loader {
605
612
  }
606
613
  let arr = Array4::from_shape_vec((n, h as usize, w as usize, 3), data)
607
614
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
608
- dict.set_item(cam, arr.into_pyarray_bound(py))?;
615
+ dict.set_item(cam, arr.into_pyarray(py))?;
609
616
  }
610
617
  }
611
618
  }
612
619
  Some(spec) => {
613
- let decoder = self.frame_decoder.as_deref_mut().expect("decoder set");
620
+ let mut decoder_guard = self
621
+ .frame_decoder
622
+ .as_ref()
623
+ .expect("decoder set")
624
+ .lock()
625
+ .expect("decoder lock poisoned");
626
+ let decoder: &mut dyn Decoder = &mut **decoder_guard;
614
627
  // camera -> per-batch-item Vec<Frame> (one per temporal step). Cheap to
615
628
  // collect: `Frame` clones only bump an `Arc` refcount.
616
629
  let mut by_camera: BTreeMap<String, Vec<Vec<Frame>>> = BTreeMap::new();
@@ -630,20 +643,20 @@ impl Loader {
630
643
  // just nested one level deeper to carry the temporal-window axis.
631
644
  for (cam, items) in by_camera {
632
645
  let steps = items.first().map(Vec::len).unwrap_or(0);
633
- let batch_list = PyList::empty_bound(py);
646
+ let batch_list = PyList::empty(py);
634
647
  for frames in &items {
635
648
  if frames.len() != steps {
636
649
  return Err(PyValueError::new_err(
637
650
  "windowed frames have inconsistent steps or dimensions",
638
651
  ));
639
652
  }
640
- let step_list = PyList::empty_bound(py);
653
+ let step_list = PyList::empty(py);
641
654
  for frame in frames {
642
655
  let (w, h) = (frame.width as usize, frame.height as usize);
643
656
  let data = frame.to_rgb24_bytes();
644
657
  let arr = Array3::from_shape_vec((h, w, 3), data)
645
658
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
646
- step_list.append(arr.into_pyarray_bound(py))?;
659
+ step_list.append(arr.into_pyarray(py))?;
647
660
  }
648
661
  batch_list.append(step_list)?;
649
662
  }
@@ -680,7 +693,7 @@ impl Loader {
680
693
  let shape = IxDyn(&[n, steps, h as usize, w as usize, 3]);
681
694
  let arr = ArrayD::from_shape_vec(shape, data)
682
695
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
683
- dict.set_item(cam, arr.into_pyarray_bound(py))?;
696
+ dict.set_item(cam, arr.into_pyarray(py))?;
684
697
  }
685
698
  }
686
699
  }
@@ -727,7 +740,7 @@ impl Loader {
727
740
 
728
741
  /// Stack a batch of samples into a dict of NumPy arrays.
729
742
  fn batch_to_dict(py: Python<'_>, samples: &[Sample]) -> PyResult<Py<PyDict>> {
730
- let dict = PyDict::new_bound(py);
743
+ let dict = PyDict::new(py);
731
744
  if samples.is_empty() {
732
745
  return Ok(dict.unbind());
733
746
  }
@@ -752,19 +765,19 @@ fn batch_to_dict(py: Python<'_>, samples: &[Sample]) -> PyResult<Py<PyDict>> {
752
765
  }
753
766
  let arr = Array2::from_shape_vec((n, dim), data)
754
767
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
755
- dict.set_item(name, arr.into_pyarray_bound(py))?;
768
+ dict.set_item(name, arr.into_pyarray(py))?;
756
769
  }
757
770
 
758
771
  // Provenance: episode index per row.
759
772
  let episodes: Vec<i64> = samples.iter().map(|s| s.episode_index as i64).collect();
760
- dict.set_item("episode_index", episodes.into_pyarray_bound(py))?;
773
+ dict.set_item("episode_index", episodes.into_pyarray(py))?;
761
774
 
762
775
  Ok(dict.unbind())
763
776
  }
764
777
 
765
778
  /// Stack windowed samples into `[batch, num_deltas, dim]` arrays per feature.
766
779
  fn windowed_batch_to_dict(py: Python<'_>, samples: &[WindowedSample]) -> PyResult<Py<PyDict>> {
767
- let dict = PyDict::new_bound(py);
780
+ let dict = PyDict::new(py);
768
781
  if samples.is_empty() {
769
782
  return Ok(dict.unbind());
770
783
  }
@@ -798,11 +811,11 @@ fn windowed_batch_to_dict(py: Python<'_>, samples: &[WindowedSample]) -> PyResul
798
811
  }
799
812
  let arr = Array3::from_shape_vec((n, nd, dim), data)
800
813
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
801
- dict.set_item(name, arr.into_pyarray_bound(py))?;
814
+ dict.set_item(name, arr.into_pyarray(py))?;
802
815
  }
803
816
 
804
817
  let episodes: Vec<i64> = samples.iter().map(|s| s.episode_index as i64).collect();
805
- dict.set_item("episode_index", episodes.into_pyarray_bound(py))?;
818
+ dict.set_item("episode_index", episodes.into_pyarray(py))?;
806
819
 
807
820
  Ok(dict.unbind())
808
821
  }
@@ -818,7 +831,7 @@ fn convert_batch(py: Python<'_>, dict: &Bound<'_, PyDict>, output: &str) -> PyRe
818
831
  other => return Err(PyValueError::new_err(format!("unknown output '{other}'"))),
819
832
  };
820
833
  let func = py
821
- .import_bound(module_name)
834
+ .import(module_name)
822
835
  .map_err(|e| {
823
836
  PyRuntimeError::new_err(format!("output='{output}' requires {module_name}: {e}"))
824
837
  })?
@@ -837,18 +850,18 @@ fn convert_batch(py: Python<'_>, dict: &Bound<'_, PyDict>, output: &str) -> PyRe
837
850
 
838
851
  /// Convert a Python-free [`RustBatch`] (raw buffers + shapes) into a dict of NumPy arrays.
839
852
  fn rustbatch_to_dict(py: Python<'_>, batch: RustBatch) -> PyResult<Py<PyDict>> {
840
- let dict = PyDict::new_bound(py);
853
+ let dict = PyDict::new(py);
841
854
  for (name, (data, shape)) in batch.features {
842
855
  let arr = ArrayD::from_shape_vec(IxDyn(&shape), data)
843
856
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
844
- dict.set_item(name, arr.into_pyarray_bound(py))?;
857
+ dict.set_item(name, arr.into_pyarray(py))?;
845
858
  }
846
859
  for (cam, (data, shape)) in batch.frames {
847
860
  let arr = ArrayD::from_shape_vec(IxDyn(&shape), data)
848
861
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
849
- dict.set_item(cam, arr.into_pyarray_bound(py))?;
862
+ dict.set_item(cam, arr.into_pyarray(py))?;
850
863
  }
851
- dict.set_item("episode_index", batch.episode_index.into_pyarray_bound(py))?;
864
+ dict.set_item("episode_index", batch.episode_index.into_pyarray(py))?;
852
865
  Ok(dict.unbind())
853
866
  }
854
867
 
@@ -871,7 +884,7 @@ impl PrefetchLoader {
871
884
  fn __next__(&mut self, py: Python<'_>) -> PyResult<Option<Py<PyDict>>> {
872
885
  // Wait for the next assembled batch with the GIL released.
873
886
  let batch = py
874
- .allow_threads(|| self.prefetcher.next_batch())
887
+ .detach(|| self.prefetcher.next_batch())
875
888
  .map_err(core_err)?;
876
889
  let Some(batch) = batch else {
877
890
  return Ok(None);
@@ -901,10 +914,10 @@ fn conversion_report_to_dict(
901
914
  py: Python<'_>,
902
915
  report: &pyroboframes_core::mcap::ConversionReport,
903
916
  ) -> PyResult<Py<PyDict>> {
904
- let out = PyDict::new_bound(py);
905
- let topics = pyo3::types::PyList::empty_bound(py);
917
+ let out = PyDict::new(py);
918
+ let topics = pyo3::types::PyList::empty(py);
906
919
  for t in &report.topics {
907
- let d = PyDict::new_bound(py);
920
+ let d = PyDict::new(py);
908
921
  d.set_item("topic", &t.topic)?;
909
922
  d.set_item("messages", t.messages)?;
910
923
  d.set_item("columns", t.columns)?;
@@ -992,7 +1005,7 @@ impl PointCloudPy {
992
1005
  }
993
1006
  let arr = Array2::from_shape_vec((self.inner.points.len(), 3), data)
994
1007
  .map_err(|e| PyValueError::new_err(e.to_string()))?;
995
- Ok(arr.into_pyarray_bound(py).unbind().into())
1008
+ Ok(arr.into_pyarray(py).unbind().into())
996
1009
  }
997
1010
 
998
1011
  fn __len__(&self) -> usize {
@@ -1030,7 +1043,7 @@ impl CameraIntrinsicsPy {
1030
1043
  let k = self.inner.k_matrix();
1031
1044
  Array2::from_shape_vec((3, 3), k.to_vec())
1032
1045
  .unwrap()
1033
- .into_pyarray_bound(py)
1046
+ .into_pyarray(py)
1034
1047
  .unbind()
1035
1048
  .into()
1036
1049
  }
@@ -1056,7 +1069,7 @@ impl CameraIntrinsicsPy {
1056
1069
  fn unproject_direction(&self, u: f64, v: f64, py: Python<'_>) -> Py<PyAny> {
1057
1070
  let dir = self.inner.unproject_direction(u, v);
1058
1071
  Array1::from_vec(dir.to_vec())
1059
- .into_pyarray_bound(py)
1072
+ .into_pyarray(py)
1060
1073
  .unbind()
1061
1074
  .into()
1062
1075
  }
@@ -1158,8 +1171,8 @@ impl CameraCalibrationPy {
1158
1171
  let origin_arr = Array1::from_vec(origin.to_vec());
1159
1172
  let dir_arr = Array1::from_vec(direction.to_vec());
1160
1173
  (
1161
- origin_arr.into_pyarray_bound(py).unbind().into(),
1162
- dir_arr.into_pyarray_bound(py).unbind().into(),
1174
+ origin_arr.into_pyarray(py).unbind().into(),
1175
+ dir_arr.into_pyarray(py).unbind().into(),
1163
1176
  )
1164
1177
  }
1165
1178
 
File without changes
File without changes