dexverse-cli 0.1.3__tar.gz → 0.1.3.post2__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 (21) hide show
  1. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/.gitignore +12 -12
  2. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/.python-version +1 -1
  3. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/PKG-INFO +3 -1
  4. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/pyproject.toml +68 -68
  5. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/README.md +109 -107
  6. dexverse_cli-0.1.3.post2/src/dexverse_cli/__init__.py +1 -0
  7. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/alignment.py +45 -45
  8. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/cli.py +194 -187
  9. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/download.py +476 -458
  10. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/hdf5_schema.py +519 -519
  11. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/http.py +416 -416
  12. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/jetson_encoder.py +168 -168
  13. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/manifest.py +274 -271
  14. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/pack.py +167 -167
  15. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/raw_schema.py +418 -418
  16. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/state.py +141 -141
  17. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/transaction.py +126 -126
  18. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/unpack.py +185 -185
  19. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/src/dexverse_cli/unversioned_hdf5.py +321 -321
  20. {dexverse_cli-0.1.3 → dexverse_cli-0.1.3.post2}/uv.lock +1 -1
  21. dexverse_cli-0.1.3/src/dexverse_cli/__init__.py +0 -1
@@ -1,12 +1,12 @@
1
- .venv/
2
- .venv-smoke/
3
- .venv-smoke-*/
4
- .smoke-work/
5
- .artifact-inspect/
6
- .manifest/
7
- .pytest_cache/
8
- .mypy_cache/
9
- .ruff_cache/
10
- __pycache__/
11
- *.py[cod]
12
- dist/
1
+ .venv/
2
+ .venv-smoke/
3
+ .venv-smoke-*/
4
+ .smoke-work/
5
+ .artifact-inspect/
6
+ .manifest/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ __pycache__/
11
+ *.py[cod]
12
+ dist/
@@ -1 +1 @@
1
- 3.10
1
+ 3.10
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: dexverse-cli
3
- Version: 0.1.3
3
+ Version: 0.1.3.post2
4
4
  Summary: Download, pack, and unpack DexVerse datasets
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: av<17,>=14
@@ -43,6 +43,8 @@ type manifest.json | dexverse-dl download --manifest - --out ./dataset
43
43
  A manifest is either a JSON file list or an object containing `files`. Each
44
44
  file requires `download_url` and `file_name`. Optional fields are
45
45
  `storage_path`, `file_size`, `sha256`, `meta_data`, and `data_protocol`.
46
+ Unknown top-level keys next to `files` (for example the `query_conditions` /
47
+ `export_info` blocks written by the web batch export) are ignored.
46
48
  `data_protocol` is retained in the downloaded metadata sidecar. Downloaded metadata is
47
49
  stored in a versioned sidecar and becomes `task_instruction.json` when the
48
50
  corresponding HDF5 file is unpacked; only top-level `data_protocol` is removed
@@ -1,68 +1,68 @@
1
- [build-system]
2
- requires = ["hatchling>=1.27"]
3
- build-backend = "hatchling.build"
4
-
5
- [project]
6
- name = "dexverse-cli"
7
- version = "0.1.3"
8
- description = "Download, pack, and unpack DexVerse datasets"
9
- readme = "src/dexverse_cli/README.md"
10
- requires-python = ">=3.10"
11
- dependencies = [
12
- "av>=14,<17",
13
- "h5py>=3.11,<4",
14
- "httpx>=0.28,<1",
15
- "numpy>=1.26,<3",
16
- "pillow>=10,<13",
17
- "rich>=13.9,<15",
18
- "typer>=0.16,<1",
19
- ]
20
-
21
- [project.optional-dependencies]
22
- jetson = [
23
- "PyGObject>=3.42,<4; platform_system == 'Linux'",
24
- ]
25
-
26
- [project.scripts]
27
- dexverse-dl = "dexverse_cli.cli:app"
28
-
29
- [dependency-groups]
30
- dev = [
31
- "mypy>=1.15,<2",
32
- "pytest>=8.3,<10",
33
- "ruff>=0.11,<1",
34
- ]
35
-
36
- [tool.hatch.build.targets.wheel]
37
- packages = ["src/dexverse_cli"]
38
-
39
- [tool.hatch.build.targets.sdist]
40
- include = [
41
- "/pyproject.toml",
42
- "/uv.lock",
43
- "/.python-version",
44
- "/src/dexverse_cli",
45
- ]
46
-
47
- [tool.pytest.ini_options]
48
- addopts = "-ra"
49
- testpaths = ["tests"]
50
-
51
- [tool.ruff]
52
- target-version = "py310"
53
- line-length = 120
54
-
55
- [tool.ruff.lint]
56
- select = ["E", "F", "I", "UP", "B", "SIM", "RUF", "TID252"]
57
-
58
- [tool.ruff.lint.flake8-tidy-imports]
59
- ban-relative-imports = "all"
60
-
61
- [tool.ruff.lint.per-file-ignores]
62
- "tests/**/*.py" = ["TID252"]
63
-
64
- [tool.mypy]
65
- python_version = "3.10"
66
- strict = true
67
- warn_unreachable = true
68
- ignore_missing_imports = true
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "dexverse-cli"
7
+ version = "0.1.3.post2"
8
+ description = "Download, pack, and unpack DexVerse datasets"
9
+ readme = "src/dexverse_cli/README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "av>=14,<17",
13
+ "h5py>=3.11,<4",
14
+ "httpx>=0.28,<1",
15
+ "numpy>=1.26,<3",
16
+ "pillow>=10,<13",
17
+ "rich>=13.9,<15",
18
+ "typer>=0.16,<1",
19
+ ]
20
+
21
+ [project.optional-dependencies]
22
+ jetson = [
23
+ "PyGObject>=3.42,<4; platform_system == 'Linux'",
24
+ ]
25
+
26
+ [project.scripts]
27
+ dexverse-dl = "dexverse_cli.cli:app"
28
+
29
+ [dependency-groups]
30
+ dev = [
31
+ "mypy>=1.15,<2",
32
+ "pytest>=8.3,<10",
33
+ "ruff>=0.11,<1",
34
+ ]
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["src/dexverse_cli"]
38
+
39
+ [tool.hatch.build.targets.sdist]
40
+ include = [
41
+ "/pyproject.toml",
42
+ "/uv.lock",
43
+ "/.python-version",
44
+ "/src/dexverse_cli",
45
+ ]
46
+
47
+ [tool.pytest.ini_options]
48
+ addopts = "-ra"
49
+ testpaths = ["tests"]
50
+
51
+ [tool.ruff]
52
+ target-version = "py310"
53
+ line-length = 120
54
+
55
+ [tool.ruff.lint]
56
+ select = ["E", "F", "I", "UP", "B", "SIM", "RUF", "TID252"]
57
+
58
+ [tool.ruff.lint.flake8-tidy-imports]
59
+ ban-relative-imports = "all"
60
+
61
+ [tool.ruff.lint.per-file-ignores]
62
+ "tests/**/*.py" = ["TID252"]
63
+
64
+ [tool.mypy]
65
+ python_version = "3.10"
66
+ strict = true
67
+ warn_unreachable = true
68
+ ignore_missing_imports = true
@@ -1,107 +1,109 @@
1
- # dexverse-cli
2
-
3
- `dexverse-cli` downloads DexVerse dataset manifests over HTTP(S), packs strict
4
- raw sessions into versioned HDF5 files, and unpacks HDF5 sessions. It requires
5
- Python 3.10 or newer.
6
-
7
- ## Install
8
-
9
- ```console
10
- pip install dexverse-cli
11
- ```
12
-
13
- ## Download
14
-
15
- Read a manifest from a file:
16
-
17
- ```console
18
- dexverse-dl download --manifest manifest.json --out ./dataset
19
- ```
20
-
21
- Or pipe a short-lived manifest directly to stdin:
22
-
23
- ```console
24
- type manifest.json | dexverse-dl download --manifest - --out ./dataset
25
- ```
26
-
27
- A manifest is either a JSON file list or an object containing `files`. Each
28
- file requires `download_url` and `file_name`. Optional fields are
29
- `storage_path`, `file_size`, `sha256`, `meta_data`, and `data_protocol`.
30
- `data_protocol` is retained in the downloaded metadata sidecar. Downloaded metadata is
31
- stored in a versioned sidecar and becomes `task_instruction.json` when the
32
- corresponding HDF5 file is unpacked; only top-level `data_protocol` is removed
33
- from that algorithm-facing projection.
34
-
35
- Downloads use bounded parallelism, retries, and compatible partial-file resume.
36
- Within a manifest, the first occurrence of a target path keeps its name; later
37
- occurrences receive `-1`, `-2`, etc. before the final extension (for example,
38
- `episode1.hdf5`, `episode1-1.hdf5`, `episode1-2.hdf5`). Numbering skips names and
39
- paths already claimed by other entries, including partial files and metadata.
40
- Different relative directories remain independent. Names are assigned in manifest
41
- order, with Windows case-insensitive matching, before any downloads start.
42
- Rerunning the same manifest preserves the assigned names for skipping and resume;
43
- existing files on disk do not trigger new suffixes. This is not cross-batch name
44
- allocation: changing the manifest entries or their order can change the mapping.
45
- When `sha256` is present it is always checked before the final file is replaced.
46
- TLS certificate verification is disabled by default for internal endpoints;
47
- pass `--secure` to enable certificate verification.
48
-
49
- ## Pack
50
-
51
- Pack one raw session, or the immediate session directories under a parent:
52
-
53
- ```console
54
- dexverse-dl pack --input ./raw/session --output ./packed --format jpeg
55
- ```
56
-
57
- JPEG is the platform-independent default. Packing validates the complete raw
58
- inventory, every image, all camera stream relationships, and pose data before
59
- transactionally replacing an output. Camera and pose counts may differ; pose is
60
- linearly aligned to the deterministic reference camera timeline.
61
-
62
- Jetson MP4 packing is optional:
63
-
64
- ```console
65
- pip install "dexverse-cli[jetson]"
66
- dexverse-dl pack --input ./raw/session --output ./packed --format video
67
- ```
68
-
69
- The Python extra does not install native Jetson GStreamer components. Video
70
- packing reports an explicit error unless the required hardware pipeline is
71
- available. JPEG packing, download, help, and unpack do not import GStreamer.
72
-
73
- ## Unpack
74
-
75
- Unpack one HDF5 file:
76
-
77
- ```console
78
- dexverse-dl unpack --input ./packed/session.hdf5 --output ./restored
79
- ```
80
-
81
- Or recursively unpack `*.hdf5` files while preserving their relative paths:
82
-
83
- ```console
84
- dexverse-dl unpack --input-dir ./packed --output ./restored
85
- ```
86
-
87
- Unpacking validates the complete versioned schema before transactionally
88
- publishing a restored session. It also retains the supported unversioned HDF5
89
- read path.
90
-
91
- ## Convert
92
-
93
- Convert one supported HDF5 file:
94
-
95
- ```console
96
- dexverse-dl convert --input ./dataset/session.hdf5 --output ./restored
97
- ```
98
-
99
- Or recursively convert `*.hdf5` files while preserving their relative paths:
100
-
101
- ```console
102
- dexverse-dl convert --input-dir ./dataset --output ./restored
103
- ```
104
-
105
- `convert` is the compatibility alias for `unpack`; it retains the same options,
106
- target mapping, legacy HDF5 support, exit codes, and `converted=...` summary.
107
- Batches continue after an item failure but exit with status 1 if any item fails.
1
+ # dexverse-cli
2
+
3
+ `dexverse-cli` downloads DexVerse dataset manifests over HTTP(S), packs strict
4
+ raw sessions into versioned HDF5 files, and unpacks HDF5 sessions. It requires
5
+ Python 3.10 or newer.
6
+
7
+ ## Install
8
+
9
+ ```console
10
+ pip install dexverse-cli
11
+ ```
12
+
13
+ ## Download
14
+
15
+ Read a manifest from a file:
16
+
17
+ ```console
18
+ dexverse-dl download --manifest manifest.json --out ./dataset
19
+ ```
20
+
21
+ Or pipe a short-lived manifest directly to stdin:
22
+
23
+ ```console
24
+ type manifest.json | dexverse-dl download --manifest - --out ./dataset
25
+ ```
26
+
27
+ A manifest is either a JSON file list or an object containing `files`. Each
28
+ file requires `download_url` and `file_name`. Optional fields are
29
+ `storage_path`, `file_size`, `sha256`, `meta_data`, and `data_protocol`.
30
+ Unknown top-level keys next to `files` (for example the `query_conditions` /
31
+ `export_info` blocks written by the web batch export) are ignored.
32
+ `data_protocol` is retained in the downloaded metadata sidecar. Downloaded metadata is
33
+ stored in a versioned sidecar and becomes `task_instruction.json` when the
34
+ corresponding HDF5 file is unpacked; only top-level `data_protocol` is removed
35
+ from that algorithm-facing projection.
36
+
37
+ Downloads use bounded parallelism, retries, and compatible partial-file resume.
38
+ Within a manifest, the first occurrence of a target path keeps its name; later
39
+ occurrences receive `-1`, `-2`, etc. before the final extension (for example,
40
+ `episode1.hdf5`, `episode1-1.hdf5`, `episode1-2.hdf5`). Numbering skips names and
41
+ paths already claimed by other entries, including partial files and metadata.
42
+ Different relative directories remain independent. Names are assigned in manifest
43
+ order, with Windows case-insensitive matching, before any downloads start.
44
+ Rerunning the same manifest preserves the assigned names for skipping and resume;
45
+ existing files on disk do not trigger new suffixes. This is not cross-batch name
46
+ allocation: changing the manifest entries or their order can change the mapping.
47
+ When `sha256` is present it is always checked before the final file is replaced.
48
+ TLS certificate verification is disabled by default for internal endpoints;
49
+ pass `--secure` to enable certificate verification.
50
+
51
+ ## Pack
52
+
53
+ Pack one raw session, or the immediate session directories under a parent:
54
+
55
+ ```console
56
+ dexverse-dl pack --input ./raw/session --output ./packed --format jpeg
57
+ ```
58
+
59
+ JPEG is the platform-independent default. Packing validates the complete raw
60
+ inventory, every image, all camera stream relationships, and pose data before
61
+ transactionally replacing an output. Camera and pose counts may differ; pose is
62
+ linearly aligned to the deterministic reference camera timeline.
63
+
64
+ Jetson MP4 packing is optional:
65
+
66
+ ```console
67
+ pip install "dexverse-cli[jetson]"
68
+ dexverse-dl pack --input ./raw/session --output ./packed --format video
69
+ ```
70
+
71
+ The Python extra does not install native Jetson GStreamer components. Video
72
+ packing reports an explicit error unless the required hardware pipeline is
73
+ available. JPEG packing, download, help, and unpack do not import GStreamer.
74
+
75
+ ## Unpack
76
+
77
+ Unpack one HDF5 file:
78
+
79
+ ```console
80
+ dexverse-dl unpack --input ./packed/session.hdf5 --output ./restored
81
+ ```
82
+
83
+ Or recursively unpack `*.hdf5` files while preserving their relative paths:
84
+
85
+ ```console
86
+ dexverse-dl unpack --input-dir ./packed --output ./restored
87
+ ```
88
+
89
+ Unpacking validates the complete versioned schema before transactionally
90
+ publishing a restored session. It also retains the supported unversioned HDF5
91
+ read path.
92
+
93
+ ## Convert
94
+
95
+ Convert one supported HDF5 file:
96
+
97
+ ```console
98
+ dexverse-dl convert --input ./dataset/session.hdf5 --output ./restored
99
+ ```
100
+
101
+ Or recursively convert `*.hdf5` files while preserving their relative paths:
102
+
103
+ ```console
104
+ dexverse-dl convert --input-dir ./dataset --output ./restored
105
+ ```
106
+
107
+ `convert` is the compatibility alias for `unpack`; it retains the same options,
108
+ target mapping, legacy HDF5 support, exit codes, and `converted=...` summary.
109
+ Batches continue after an item failure but exit with status 1 if any item fails.
@@ -0,0 +1 @@
1
+ __version__ = "0.1.3.post2"
@@ -1,45 +1,45 @@
1
- from __future__ import annotations
2
-
3
- from dataclasses import dataclass
4
-
5
- import numpy as np
6
- import numpy.typing as npt
7
-
8
- from dexverse_cli.raw_schema import RawSessionV1
9
-
10
-
11
- @dataclass(frozen=True, slots=True)
12
- class AlignedPoseV1:
13
- data: npt.NDArray[np.float32]
14
- timestamps: npt.NDArray[np.uint64]
15
- columns: tuple[str, ...]
16
-
17
-
18
- class PackAlignmentPolicyV1:
19
- """Linearly align pose values to the deterministic reference camera timeline."""
20
-
21
- name = "linear_pose_to_reference_camera_v1"
22
-
23
- def align(self, session: RawSessionV1) -> AlignedPoseV1:
24
- target = np.asarray(
25
- [record.timestamp for record in session.records_by_camera[session.reference_camera]],
26
- dtype=np.float64,
27
- )
28
- timestamps = np.asarray(
29
- [record.timestamp_ns for record in session.records_by_camera[session.reference_camera]],
30
- dtype=np.uint64,
31
- )
32
- columns = session.pose_columns
33
- result = np.empty((target.size, len(columns)), dtype=np.float32)
34
- source_times = np.asarray([frame.timestamp for frame in session.pose_frames], dtype=np.float64)
35
- for column_index, column in enumerate(columns):
36
- values = np.asarray(
37
- [frame.data[column] for frame in session.pose_frames],
38
- dtype=np.float64,
39
- )
40
- if values.size == 1:
41
- aligned = np.full(target.shape, values[0], dtype=np.float64)
42
- else:
43
- aligned = np.interp(target, source_times, values)
44
- result[:, column_index] = aligned.astype(np.float32)
45
- return AlignedPoseV1(result, timestamps, columns)
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ import numpy as np
6
+ import numpy.typing as npt
7
+
8
+ from dexverse_cli.raw_schema import RawSessionV1
9
+
10
+
11
+ @dataclass(frozen=True, slots=True)
12
+ class AlignedPoseV1:
13
+ data: npt.NDArray[np.float32]
14
+ timestamps: npt.NDArray[np.uint64]
15
+ columns: tuple[str, ...]
16
+
17
+
18
+ class PackAlignmentPolicyV1:
19
+ """Linearly align pose values to the deterministic reference camera timeline."""
20
+
21
+ name = "linear_pose_to_reference_camera_v1"
22
+
23
+ def align(self, session: RawSessionV1) -> AlignedPoseV1:
24
+ target = np.asarray(
25
+ [record.timestamp for record in session.records_by_camera[session.reference_camera]],
26
+ dtype=np.float64,
27
+ )
28
+ timestamps = np.asarray(
29
+ [record.timestamp_ns for record in session.records_by_camera[session.reference_camera]],
30
+ dtype=np.uint64,
31
+ )
32
+ columns = session.pose_columns
33
+ result = np.empty((target.size, len(columns)), dtype=np.float32)
34
+ source_times = np.asarray([frame.timestamp for frame in session.pose_frames], dtype=np.float64)
35
+ for column_index, column in enumerate(columns):
36
+ values = np.asarray(
37
+ [frame.data[column] for frame in session.pose_frames],
38
+ dtype=np.float64,
39
+ )
40
+ if values.size == 1:
41
+ aligned = np.full(target.shape, values[0], dtype=np.float64)
42
+ else:
43
+ aligned = np.interp(target, source_times, values)
44
+ result[:, column_index] = aligned.astype(np.float32)
45
+ return AlignedPoseV1(result, timestamps, columns)