dexverse-cli 0.1.3.post1__tar.gz → 0.1.4__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.
- {dexverse_cli-0.1.3.post1 → dexverse_cli-0.1.4}/.gitignore +12 -12
- {dexverse_cli-0.1.3.post1 → dexverse_cli-0.1.4}/.python-version +1 -1
- dexverse_cli-0.1.4/PKG-INFO +301 -0
- {dexverse_cli-0.1.3.post1 → dexverse_cli-0.1.4}/pyproject.toml +69 -68
- dexverse_cli-0.1.4/src/dexverse_cli/README.md +286 -0
- dexverse_cli-0.1.4/src/dexverse_cli/__init__.py +1 -0
- dexverse_cli-0.1.4/src/dexverse_cli/cli.py +236 -0
- dexverse_cli-0.1.4/src/dexverse_cli/common/__init__.py +24 -0
- dexverse_cli-0.1.4/src/dexverse_cli/common/hashes.py +87 -0
- {dexverse_cli-0.1.3.post1/src/dexverse_cli → dexverse_cli-0.1.4/src/dexverse_cli/common}/state.py +141 -141
- dexverse_cli-0.1.4/src/dexverse_cli/download/__init__.py +16 -0
- dexverse_cli-0.1.4/src/dexverse_cli/download/batch.py +246 -0
- dexverse_cli-0.1.4/src/dexverse_cli/download/filesystem.py +190 -0
- {dexverse_cli-0.1.3.post1/src/dexverse_cli → dexverse_cli-0.1.4/src/dexverse_cli/download}/http.py +467 -416
- {dexverse_cli-0.1.3.post1/src/dexverse_cli → dexverse_cli-0.1.4/src/dexverse_cli/download}/manifest.py +356 -271
- dexverse_cli-0.1.4/src/dexverse_cli/download/runner.py +110 -0
- dexverse_cli-0.1.4/src/dexverse_cli/download/transfer.py +274 -0
- dexverse_cli-0.1.4/src/dexverse_cli/progress/__init__.py +25 -0
- dexverse_cli-0.1.4/src/dexverse_cli/progress/bar.py +144 -0
- dexverse_cli-0.1.4/src/dexverse_cli/progress/formatting.py +58 -0
- dexverse_cli-0.1.4/src/dexverse_cli/progress/reporter.py +434 -0
- dexverse_cli-0.1.4/src/dexverse_cli/progress/view.py +113 -0
- dexverse_cli-0.1.4/src/dexverse_cli/restore/__init__.py +15 -0
- {dexverse_cli-0.1.3.post1/src/dexverse_cli → dexverse_cli-0.1.4/src/dexverse_cli/restore}/alignment.py +45 -45
- dexverse_cli-0.1.4/src/dexverse_cli/restore/batch.py +116 -0
- dexverse_cli-0.1.4/src/dexverse_cli/restore/instruction.py +43 -0
- dexverse_cli-0.1.3.post1/src/dexverse_cli/raw_schema.py → dexverse_cli-0.1.4/src/dexverse_cli/restore/layout.py +418 -418
- dexverse_cli-0.1.3.post1/src/dexverse_cli/unversioned_hdf5.py → dexverse_cli-0.1.4/src/dexverse_cli/restore/legacy.py +301 -321
- dexverse_cli-0.1.4/src/dexverse_cli/restore/media.py +54 -0
- dexverse_cli-0.1.3.post1/src/dexverse_cli/transaction.py → dexverse_cli-0.1.4/src/dexverse_cli/restore/publish.py +142 -126
- dexverse_cli-0.1.4/src/dexverse_cli/restore/runner.py +70 -0
- dexverse_cli-0.1.3.post1/src/dexverse_cli/hdf5_schema.py → dexverse_cli-0.1.4/src/dexverse_cli/restore/schema.py +514 -519
- dexverse_cli-0.1.4/src/dexverse_cli/restore/session.py +43 -0
- dexverse_cli-0.1.4/src/dexverse_cli/restore/versioned.py +79 -0
- dexverse_cli-0.1.4/src/dexverse_cli/update/__init__.py +1 -0
- dexverse_cli-0.1.4/src/dexverse_cli/update/check.py +355 -0
- dexverse_cli-0.1.4/src/dexverse_cli/update/gate.py +96 -0
- dexverse_cli-0.1.4/src/dexverse_cli/update/observation.py +244 -0
- dexverse_cli-0.1.4/src/dexverse_cli/update/upgrade.py +203 -0
- {dexverse_cli-0.1.3.post1 → dexverse_cli-0.1.4}/uv.lock +3 -24
- dexverse_cli-0.1.3.post1/PKG-INFO +0 -123
- dexverse_cli-0.1.3.post1/src/dexverse_cli/README.md +0 -107
- dexverse_cli-0.1.3.post1/src/dexverse_cli/__init__.py +0 -1
- dexverse_cli-0.1.3.post1/src/dexverse_cli/cli.py +0 -194
- dexverse_cli-0.1.3.post1/src/dexverse_cli/download.py +0 -476
- dexverse_cli-0.1.3.post1/src/dexverse_cli/jetson_encoder.py +0 -168
- dexverse_cli-0.1.3.post1/src/dexverse_cli/pack.py +0 -167
- dexverse_cli-0.1.3.post1/src/dexverse_cli/unpack.py +0 -185
|
@@ -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
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: dexverse-cli
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Download DexVerse dataset manifests and unpack HDF5 sessions
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: av<17,>=14
|
|
7
|
+
Requires-Dist: h5py<4,>=3.11
|
|
8
|
+
Requires-Dist: httpx<1,>=0.28
|
|
9
|
+
Requires-Dist: numpy<3,>=1.26
|
|
10
|
+
Requires-Dist: packaging<27,>=24
|
|
11
|
+
Requires-Dist: pillow<13,>=10
|
|
12
|
+
Requires-Dist: rich<15,>=13.9
|
|
13
|
+
Requires-Dist: typer<1,>=0.16
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# dexverse-cli
|
|
17
|
+
|
|
18
|
+
dexverse-cli downloads DexVerse dataset manifests over HTTP(S) and unpacks
|
|
19
|
+
HDF5 sessions back to the restored dataset layout. It requires
|
|
20
|
+
Python 3.10 or newer.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```console
|
|
26
|
+
pip install dexverse-cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Automatic updates
|
|
30
|
+
|
|
31
|
+
Every business command (`download`, `unpack`, `convert`) first asks whether a
|
|
32
|
+
newer `dexverse-cli` is published. Public PyPI is asked first, because that is
|
|
33
|
+
where a new release appears immediately; when PyPI cannot be reached the check
|
|
34
|
+
falls back to the source this machine's pip is configured with (`pip.conf`,
|
|
35
|
+
`PIP_INDEX_URL`, mirrors, proxies). The check is bounded to about two seconds.
|
|
36
|
+
|
|
37
|
+
- Nothing new, or nothing to ask: the command runs as usual.
|
|
38
|
+
- A newer release exists: the CLI upgrades itself in place with
|
|
39
|
+
`python -m pip install --upgrade dexverse-cli` from the source that answered,
|
|
40
|
+
and then exits with status **20**. Run the same command again; the rerun uses
|
|
41
|
+
the new version.
|
|
42
|
+
- The check times out, pip is missing, no source answers, or the upgrade fails:
|
|
43
|
+
one line is printed and the requested command still runs.
|
|
44
|
+
|
|
45
|
+
The switch is on by default. Turn the check off for one command, or permanently:
|
|
46
|
+
|
|
47
|
+
```console
|
|
48
|
+
dexverse-dl download --manifest manifest.json --out ./dataset --no-update-check
|
|
49
|
+
set DEXVERSE_CLI_UPDATE=off :: Windows (export ... on Linux and macOS)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
To pin one command — or a whole machine — to a specific source instead:
|
|
53
|
+
|
|
54
|
+
```console
|
|
55
|
+
dexverse-dl download --manifest manifest.json --out ./dataset --update-index-url https://mirror.internal/simple
|
|
56
|
+
set DEXVERSE_CLI_UPDATE_INDEX_URL=https://mirror.internal/simple
|
|
57
|
+
set DEXVERSE_CLI_UPDATE_EXTRA_INDEX_URL=https://mirror.internal/simple
|
|
58
|
+
set DEXVERSE_CLI_UPDATE_TRUSTED_HOST=mirror.internal
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The flag is shorthand for `DEXVERSE_CLI_UPDATE_INDEX_URL`. Naming any of these
|
|
62
|
+
replaces both defaults: pip is asked only there, which is also how to skip the
|
|
63
|
+
PyPI attempt on a network that cannot reach it.
|
|
64
|
+
|
|
65
|
+
`dexverse-dl --update-status` prints the recorded observation as JSON without any
|
|
66
|
+
network access or change: whether the switch is on, which source a check would
|
|
67
|
+
use (`update_source`, either `pip` or the index you named), how this interpreter
|
|
68
|
+
was installed (`install_mode`), and the last upgrade this environment performed,
|
|
69
|
+
if any. A command that changes nothing records nothing, so it leaves no directory
|
|
70
|
+
behind. `dexverse-dl --version` never checks. Pre-releases are ignored unless you
|
|
71
|
+
set `DEXVERSE_CLI_UPDATE_PRERELEASE=1`, and a working copy (`pip install -e .`,
|
|
72
|
+
`install_mode: source`) is never checked or upgraded automatically.
|
|
73
|
+
|
|
74
|
+
## Download
|
|
75
|
+
|
|
76
|
+
Read a manifest from a file:
|
|
77
|
+
|
|
78
|
+
```console
|
|
79
|
+
dexverse-dl download --manifest manifest.json --out ./dataset
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Or pipe a short-lived manifest directly to stdin:
|
|
83
|
+
|
|
84
|
+
```console
|
|
85
|
+
type manifest.json | dexverse-dl download --manifest - --out ./dataset
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A manifest is either a JSON file list or an object containing `files`. Each
|
|
89
|
+
file requires `download_url` and `file_name`. Optional fields are
|
|
90
|
+
`storage_path`, `file_size`, `sha256`, `hash`, `hash_type`, `meta_data`, and
|
|
91
|
+
`data_protocol`. Unknown top-level keys next to `files` (for example the
|
|
92
|
+
`query_conditions` / `export_info` blocks written by the web batch export) are
|
|
93
|
+
ignored. `data_protocol` is retained in the downloaded metadata sidecar.
|
|
94
|
+
Downloaded metadata is stored in a versioned sidecar and becomes
|
|
95
|
+
`task_instruction.json` when the corresponding HDF5 file is unpacked; only
|
|
96
|
+
top-level `data_protocol` is removed from that algorithm-facing projection.
|
|
97
|
+
|
|
98
|
+
### Digests
|
|
99
|
+
|
|
100
|
+
A manifest may declare one digest per file. `hash` and `hash_type` are a pair
|
|
101
|
+
and must appear together, so the tool never guesses an algorithm; the legacy
|
|
102
|
+
`sha256` field is the one exception, since its name already carries the type.
|
|
103
|
+
Three types are accepted:
|
|
104
|
+
|
|
105
|
+
| `hash_type` | Meaning | Verification cost |
|
|
106
|
+
| --- | --- | --- |
|
|
107
|
+
| `sha256` | Whole-file SHA-256 | Reads the whole file after download |
|
|
108
|
+
| `md5` | Whole-file MD5, for older records | Reads the whole file after download |
|
|
109
|
+
| `sample_sha256_v1` | Bounded sample over the head, middle, and tail 1 MiB blocks, framed with the file size | Reads at most 3 MiB per file |
|
|
110
|
+
|
|
111
|
+
`sample_sha256_v1` matches the digest the uploader and the web console already
|
|
112
|
+
produce, so their recorded value can be reused directly. It is a deduplication
|
|
113
|
+
fingerprint, not a full checksum: a change outside the sampled windows cannot be
|
|
114
|
+
detected. It does catch truncation and any change inside a sampled window.
|
|
115
|
+
`md5` is fine for detecting transfer corruption but is weak against a deliberate
|
|
116
|
+
collision, so it is not a security boundary.
|
|
117
|
+
|
|
118
|
+
Digests are **not** checked unless you ask for it, because hashing large files
|
|
119
|
+
costs real time:
|
|
120
|
+
|
|
121
|
+
```console
|
|
122
|
+
dexverse-dl download --manifest manifest.json --out ./dataset --verify
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Without `--verify`, only `file_size` is enforced (when the manifest declares
|
|
126
|
+
it), and the download state records no digest — so a later `--verify` run still
|
|
127
|
+
rechecks the file instead of trusting an unchecked claim. With `--verify`, a
|
|
128
|
+
mismatch removes the partial and fails that file.
|
|
129
|
+
|
|
130
|
+
The download command renders one progress display per batch: a batch line
|
|
131
|
+
(percent, file counter, transferred bytes, rate, remaining time, elapsed time)
|
|
132
|
+
and a line naming the current file. A retry prints a single persistent warning
|
|
133
|
+
above the display and updates the same progress line, so no second progress bar
|
|
134
|
+
is ever added:
|
|
135
|
+
|
|
136
|
+
```console
|
|
137
|
+
Download ━━━━━━━━━━━━━━─────────────────────── 38% 13/33 88.0 GB/228.3 GB 19.4 MB/s 1:15:47 < 2:00:49
|
|
138
|
+
downloading: piper_v02_0920_raw/episode_000007.hdf5
|
|
139
|
+
warning: retrying piper_v02_0920_raw/episode_000012.hdf5 (attempt 2/5) in 2.0s: transient HTTP status 503
|
|
140
|
+
Download ━━━━━━━━━━━━━━──────────────────────── 38% 13/33 1 failed 88.0 GB/228.3 GB 19.4 MB/s 1:15:47 < 2:00:49
|
|
141
|
+
retrying: piper_v02_0920_raw/episode_000012.hdf5 (retry 2/5) - transient HTTP status 503; next attempt in 2.0s
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The bar is a filled rail drawn with rich's own glyphs: `━` for a filled cell and
|
|
145
|
+
`─` for the rest. There is no frame around it, and no mark drawn inside the empty
|
|
146
|
+
part either: unlike a space-filled bar the rail delimits itself, which is why
|
|
147
|
+
`pip`, `rich`, and `tqdm` leave the brackets out. rich builds its rail from one
|
|
148
|
+
glyph and shows the split with colour, which is why rich can afford half cells;
|
|
149
|
+
here the two weights carry the split, and that rules half cells out. A half cell of
|
|
150
|
+
fill is heavy on one side of its cell and blank on the other, while a light rail
|
|
151
|
+
can only start at the next boundary, so the junction gains and loses half a cell
|
|
152
|
+
as the fill crosses each one — a notch that blinks. The fill therefore ends on
|
|
153
|
+
cell boundaries only and meets the rail directly, so every frame has one junction
|
|
154
|
+
shape and only its position moves; the percentage and byte counters carry the finer
|
|
155
|
+
resolution. Holding a permanent half-cell gap open at the junction was tried as
|
|
156
|
+
well, and reads worse than meeting flush, so there is none. The fill is drawn in
|
|
157
|
+
the line's own colour and only the rest of the rail steps back to a dim shade, so
|
|
158
|
+
the bar never competes with the numbers. Because the empty part differs by glyph
|
|
159
|
+
and not by colour alone, progress stays readable in a piped log and under
|
|
160
|
+
`NO_COLOR`. Counters and byte totals carry no words — `13/33` and
|
|
161
|
+
`88.0 GB/228.3 GB` are self-describing, as they are in every common progress
|
|
162
|
+
line — and the two clocks are paired the way `tqdm` pairs them, elapsed on the
|
|
163
|
+
left of `<` and remaining on the right, so neither needs a label and neither can
|
|
164
|
+
be mistaken for the other. The right side stays `--:--` while the total is
|
|
165
|
+
incomplete, since only a complete total yields an estimate.
|
|
166
|
+
|
|
167
|
+
The rail keeps one length for the whole batch: the first frame fixes it, so a
|
|
168
|
+
field that appears or grows mid-run (a failure count, a byte total crossing into
|
|
169
|
+
the next unit, the elapsed clock) cannot take cells from it. A shorter bar would
|
|
170
|
+
re-render a shorter fill and read as progress going backwards. That first frame
|
|
171
|
+
also holds room for the failure count before anything has failed, so the first
|
|
172
|
+
failure cannot push the remaining time off the end of the line. Only a terminal
|
|
173
|
+
resize measures the rail again, and on a narrow terminal the tail is clipped
|
|
174
|
+
before the rail is. The rail is up to 40 cells — long enough that the first one
|
|
175
|
+
fills at about 2.5%, since a bar that only starts moving at 4% is doing less to
|
|
176
|
+
calm the wait than it could — and it takes whatever fewer columns a narrow
|
|
177
|
+
terminal leaves over.
|
|
178
|
+
|
|
179
|
+
The live region is rebuilt on rich's refresh tick as well as whenever new state
|
|
180
|
+
arrives, so the elapsed clock keeps counting while one file is being worked on.
|
|
181
|
+
Without that tick the clock would freeze between callbacks and then jump by the
|
|
182
|
+
length of the file, which reads as a stall.
|
|
183
|
+
|
|
184
|
+
Percent, byte counters, and the bar follow transferred bytes; the file counter
|
|
185
|
+
advances when a file is published or skipped. When the manifest omits
|
|
186
|
+
`file_size` for any entry, the total is shown as a lower bound (`~6.3 GB`) that
|
|
187
|
+
grows as each transfer reports its real size, and the bar stays an empty rail
|
|
188
|
+
rather than filling against a bound that is still growing; percent and remaining
|
|
189
|
+
time are withheld until the total is complete instead of being guessed from a
|
|
190
|
+
partial sum. Pass `--probe-sizes` to read those sizes from the server first (one
|
|
191
|
+
small ranged request per entry that lacks one), so the total, percentage, and
|
|
192
|
+
remaining time are correct before the first byte moves:
|
|
193
|
+
|
|
194
|
+
```console
|
|
195
|
+
dexverse-dl download --manifest manifest.json --out ./dataset --probe-sizes
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The probe is off by default because a complete manifest needs no extra requests.
|
|
199
|
+
It costs one `GET` with `Range: bytes=0-0` per unknown entry and tolerates a
|
|
200
|
+
server that ignores the range. Piped or logged output (no terminal) prints the
|
|
201
|
+
same line periodically instead of repainting in place, so redirecting to a file
|
|
202
|
+
stays readable.
|
|
203
|
+
|
|
204
|
+
Pass `--no-progress` to suppress the live display, the per-file line, and retry
|
|
205
|
+
warnings while keeping the final summary:
|
|
206
|
+
|
|
207
|
+
```console
|
|
208
|
+
dexverse-dl download --manifest manifest.json --out ./dataset --no-progress
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
Downloads use bounded parallelism, retries, and compatible partial-file resume.
|
|
213
|
+
Within a manifest, the first occurrence of a target path keeps its name; later
|
|
214
|
+
occurrences receive `-1`, `-2`, etc. before the final extension (for example,
|
|
215
|
+
`episode1.hdf5`, `episode1-1.hdf5`, `episode1-2.hdf5`). Numbering skips names and
|
|
216
|
+
paths already claimed by other entries, including partial files and metadata.
|
|
217
|
+
Different relative directories remain independent. Names are assigned in manifest
|
|
218
|
+
order, with Windows case-insensitive matching, before any downloads start.
|
|
219
|
+
Rerunning the same manifest preserves the assigned names for skipping and resume;
|
|
220
|
+
existing files on disk do not trigger new suffixes. This is not cross-batch name
|
|
221
|
+
allocation: changing the manifest entries or their order can change the mapping.
|
|
222
|
+
When a digest is declared it is checked only under `--verify`; without it a file
|
|
223
|
+
is accepted on its declared `file_size` alone. TLS certificate verification is
|
|
224
|
+
disabled by default for internal endpoints; pass `--secure` to enable
|
|
225
|
+
certificate verification.
|
|
226
|
+
|
|
227
|
+
## Unpack
|
|
228
|
+
|
|
229
|
+
Unpack one HDF5 file to the restored raw dataset layout:
|
|
230
|
+
|
|
231
|
+
```console
|
|
232
|
+
dexverse-dl unpack --input ./packed/session.hdf5 --output ./restored
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Or unpack every `*.hdf5` under a directory, preserving relative paths:
|
|
236
|
+
|
|
237
|
+
```console
|
|
238
|
+
dexverse-dl unpack --input-dir ./packed --output ./restored
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Unpacking validates the complete versioned schema before transactionally
|
|
242
|
+
publishing a restored session, and retains the supported unversioned HDF5 read
|
|
243
|
+
path. It accepts `--progress/--no-progress`; the batch line reports the same
|
|
244
|
+
filled rail as the download command, driven by restored sessions, plus the
|
|
245
|
+
session count, the restored frame count, and the elapsed time:
|
|
246
|
+
|
|
247
|
+
```console
|
|
248
|
+
Unpacking ━━━━━━━━━━━━━─────────────────────────── 33% 3/9 1200 frames restored 00:42
|
|
249
|
+
packed/episode_000003.hdf5 -> restored/episode_000003
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The rail is empty until the first callback reports how many sessions the input
|
|
253
|
+
holds, and shows `?%` until then. That batch has no rate, so it has no estimate
|
|
254
|
+
and only one clock, printed bare because there is nothing to tell it apart from.
|
|
255
|
+
The frame count is the running total over the whole batch, not the count for the
|
|
256
|
+
session named on the line below it, which is why it is spelled out as `frames
|
|
257
|
+
restored`: it only ever counts sessions that finished, so a failed session adds
|
|
258
|
+
nothing, and it reaches its final value in the summary line. It is always printed,
|
|
259
|
+
even at zero, so the line keeps one shape from the first frame to the last.
|
|
260
|
+
Batches continue after an item failure but exit with status 1 if any item fails.
|
|
261
|
+
|
|
262
|
+
## Convert
|
|
263
|
+
|
|
264
|
+
`convert` is kept as a compatibility alias for `unpack`, because pipelines that
|
|
265
|
+
were written against the earlier releases still call it. It takes the same
|
|
266
|
+
options and performs the same restore:
|
|
267
|
+
|
|
268
|
+
```console
|
|
269
|
+
dexverse-dl convert --input ./packed/session.hdf5 --output ./restored
|
|
270
|
+
dexverse-dl convert --input-dir ./packed --output ./restored
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Its only differences are the labels on the progress line and in the summary:
|
|
274
|
+
`Converting` and `converted=` instead of `Unpacking` and `unpacked=`. New
|
|
275
|
+
scripts should prefer `unpack`.
|
|
276
|
+
|
|
277
|
+
## Code layout
|
|
278
|
+
|
|
279
|
+
`cli.py` only wires typer to the chains; everything else lives in the package for
|
|
280
|
+
the chain it belongs to, and the two chains never import each other.
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
dexverse_cli/
|
|
284
|
+
cli.py download / unpack / convert, and nothing else
|
|
285
|
+
common/ what both chains share: the .dexverse state directory, digests
|
|
286
|
+
progress/ what a running command shows: views, the rail, the reporters
|
|
287
|
+
view.py the frozen snapshots a batch hands to its display
|
|
288
|
+
bar.py the rail's glyphs, geometry, and styling
|
|
289
|
+
formatting.py byte counts and clocks as the lines show them
|
|
290
|
+
reporter.py the live two-line region and the reports that drive it
|
|
291
|
+
download/ manifest -> plan -> one file -> batch -> runner
|
|
292
|
+
restore/ session format -> raw layout -> publish -> batch -> runner
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Each chain follows the same shape, so a reader who knows one knows the other: an
|
|
296
|
+
input contract (`download/manifest.py`, `restore/schema.py`), a plan
|
|
297
|
+
(`download/filesystem.py`, `restore/versioned.py`), the work for one item
|
|
298
|
+
(`download/transfer.py` `FileTransfer`, `restore/session.py` `SessionRestore`), the
|
|
299
|
+
one owner of the batch's state and counters (`*/batch.py`), and the orchestration
|
|
300
|
+
that decides the order (`*/runner.py`).
|
|
301
|
+
|
|
@@ -1,68 +1,69 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["hatchling>=1.27"]
|
|
3
|
-
build-backend = "hatchling.build"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "dexverse-cli"
|
|
7
|
-
|
|
8
|
-
description = "Download
|
|
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
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
[
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"/
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dexverse-cli"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Download DexVerse dataset manifests and unpack HDF5 sessions"
|
|
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
|
+
"packaging>=24,<27",
|
|
17
|
+
"pillow>=10,<13",
|
|
18
|
+
"rich>=13.9,<15",
|
|
19
|
+
"typer>=0.16,<1",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
dexverse-dl = "dexverse_cli.cli:app"
|
|
24
|
+
|
|
25
|
+
[dependency-groups]
|
|
26
|
+
dev = [
|
|
27
|
+
"mypy>=1.15,<2",
|
|
28
|
+
"pytest>=8.3,<10",
|
|
29
|
+
"ruff>=0.11,<1",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[tool.hatch.version]
|
|
33
|
+
# One version, declared once: the build backend reads the package marker, so a
|
|
34
|
+
# release bump cannot leave the wheel metadata disagreeing with the code.
|
|
35
|
+
path = "src/dexverse_cli/__init__.py"
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.wheel]
|
|
38
|
+
packages = ["src/dexverse_cli"]
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.sdist]
|
|
41
|
+
include = [
|
|
42
|
+
"/pyproject.toml",
|
|
43
|
+
"/uv.lock",
|
|
44
|
+
"/.python-version",
|
|
45
|
+
"/src/dexverse_cli",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[tool.pytest.ini_options]
|
|
49
|
+
addopts = "-ra"
|
|
50
|
+
testpaths = ["tests"]
|
|
51
|
+
|
|
52
|
+
[tool.ruff]
|
|
53
|
+
target-version = "py310"
|
|
54
|
+
line-length = 120
|
|
55
|
+
|
|
56
|
+
[tool.ruff.lint]
|
|
57
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "RUF", "TID252"]
|
|
58
|
+
|
|
59
|
+
[tool.ruff.lint.flake8-tidy-imports]
|
|
60
|
+
ban-relative-imports = "all"
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint.per-file-ignores]
|
|
63
|
+
"tests/**/*.py" = ["TID252"]
|
|
64
|
+
|
|
65
|
+
[tool.mypy]
|
|
66
|
+
python_version = "3.10"
|
|
67
|
+
strict = true
|
|
68
|
+
warn_unreachable = true
|
|
69
|
+
ignore_missing_imports = true
|