diff --git a/Taskfile.yml b/Taskfile.yml index c3855df9..60073d11 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -34,6 +34,19 @@ tasks: cmds: - nice -n 10 uv run python scripts/micro_mint_rig.py {{.CLI_ARGS}} + rig:micro: + desc: | + pgw#997 — the same full cycle against `examples/micro-diffusion`, the + org-worker-shaped endpoint: 3 export entries (two fork arms + a second + target), CONTAINER inputs with a plain input after them so every cycle + re-proves pgw#993/pgw#994, deterministically GENERATED weights, and a + parity check that arms the adopted cell and compares every arm to eager. + + This is the vehicle a mint-path change should be proven against; + `task rig:mint` is the cheaper one-entry plumbing toy. + cmds: + - nice -n 10 uv run python scripts/micro_mint_rig.py --vehicle micro {{.CLI_ARGS}} + rig:test: desc: | pgw#978 — the rig as a pytest row, including the full cycle (opt-in via diff --git a/changelog.d/pgw997.md b/changelog.d/pgw997.md new file mode 100644 index 00000000..6123b7e2 --- /dev/null +++ b/changelog.d/pgw997.md @@ -0,0 +1,23 @@ +### Added + +- **A micro endpoint family, so an AOT mint cycle costs seconds instead of + hours (pgw#997).** `examples/micro-diffusion` is a real org worker — its own + `pyproject.toml`, `endpoint.toml`, Dockerfile-first build, catalog slot, + registered export declaration — that declares **3 export entries** over a + 1.1 MB deterministically generated checkpoint. sdxl declares 36 and costs + ~95 minutes a pod cycle; the full local machinery cycle against this family + is **15 s**, including a parity check that arms the adopted cell in a second + process and compares every arm to eager (max |delta| 7.2e-07). +- The declaration deliberately keeps the container-flattening seam under test + on every cycle: a `repeat=` container input with a **plain input immediately + after it** (pgw#994's shape), and one `Dim` carried by both a container + element axis and a plain tensor axis (pgw#993's). +- **`task rig:micro`** runs the pgw#978 rig against it; `scripts/micro_mint_rig.py` + gained `--vehicle {tiny,micro}` and its endpoint coupling moved into + `tests/harness/rig_vehicles.py`. `task rig:mint` is unchanged. + +### Fixed + +- The rig's adopt leg now installs the same runtime probes the mint child got + and configures logging, so a filter miss reports the axis it was rejected on + instead of an empty log. diff --git a/docs/probe-worker.md b/docs/probe-worker.md index ef11c069..ec7d2144 100644 --- a/docs/probe-worker.md +++ b/docs/probe-worker.md @@ -11,7 +11,8 @@ Tier by tier, cheapest first: | Tier | Cost per iteration | Covers | |---|---|---| -| `task rig:mint` (pgw#978) | seconds, free | resolve, handoff, spawn, load, warm, export, compile, seal, publish, adopt — on a toy model | +| `task rig:mint` (pgw#978) | seconds, free | resolve, handoff, spawn, load, warm, export, compile, seal, publish, adopt — on a toy model, ONE export entry | +| `task rig:micro` (pgw#997) | ~15 s, free | all of the above on a REAL org-worker package — 3 entries, two fork arms, a second target, container inputs, a derived dynamic range, plus a PARITY check that arms the adopted cell and compares every arm to eager | | experimental image (pgw#979) | one image build | the real image, the real deps, a real pod, a real family | | **probe pod (this doc)** | seconds, on a pod you already hold | everything above, on real weights and a real card, iterating | diff --git a/examples/micro-diffusion/.dockerignore b/examples/micro-diffusion/.dockerignore new file mode 100644 index 00000000..853fa991 --- /dev/null +++ b/examples/micro-diffusion/.dockerignore @@ -0,0 +1,5 @@ +.venv/ +.mypy_cache/ +__pycache__/ +*.pyc +.micro-weights/ diff --git a/examples/micro-diffusion/Dockerfile b/examples/micro-diffusion/Dockerfile new file mode 100644 index 00000000..6e23782c --- /dev/null +++ b/examples/micro-diffusion/Dockerfile @@ -0,0 +1,46 @@ +# The three Dockerfile contract points (docs/dockerfile.md), plus one thing +# only this family does: it GENERATES its checkpoint at build time. +# +# The generation step is what keeps the family compliant with the +# weights-locality rule while still being a real endpoint. There is no +# checkpoint in git, none on a developer's box, and no download at boot — the +# bytes are a pure function of a seed, materialized into the image once, and +# byte-identical in every image built from this Dockerfile. +ARG BASE_IMAGE=pytorch/pytorch:2.13.0-cuda13.0-cudnn9-runtime +FROM ${BASE_IMAGE} + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv + +WORKDIR /app + +COPY pyproject.toml uv.lock /app/ + +RUN --mount=type=cache,id=cozy-uv-cache,target=/var/cache/uv,sharing=locked \ + uv export --cache-dir /var/cache/uv --link-mode copy \ + --no-dev --no-hashes --no-sources --no-emit-project --no-emit-local \ + -o /tmp/requirements.txt \ + && uv pip install --cache-dir /var/cache/uv --link-mode copy \ + --system --break-system-packages --no-deps -r /tmp/requirements.txt + +COPY . /app + +RUN --mount=type=cache,id=cozy-uv-cache,target=/var/cache/uv,sharing=locked \ + uv pip install --cache-dir /var/cache/uv --link-mode copy \ + --system --break-system-packages --no-deps --no-sources /app + +# The checkpoint, generated and VERIFIED in the same layer. `--verify` +# regenerates every tensor and byte-compares: an image whose weights did not +# reproduce from the seed fails the build instead of shipping a checkpoint +# nobody else can rebuild. +ARG MICRO_SEED=997 +RUN python -m micro_diffusion.weights --out /app/.micro-weights \ + --seed ${MICRO_SEED} --verify + +# Contract point 2: discovery baked into the image. +ARG BUILD_NONCE=2026-08-06-default +RUN echo "build-nonce=${BUILD_NONCE}" \ + && mkdir -p /app/.tensorhub \ + && python -m gen_worker.discovery > /app/.tensorhub/endpoint.lock + +# Contract point 3. +ENTRYPOINT ["python", "-m", "gen_worker.entrypoint"] diff --git a/examples/micro-diffusion/README.md b/examples/micro-diffusion/README.md new file mode 100644 index 00000000..d22a18ae --- /dev/null +++ b/examples/micro-diffusion/README.md @@ -0,0 +1,198 @@ +# micro-diffusion — the fleet's smallest REAL endpoint family + +**Why it exists.** AOT-mint iteration has been using sdxl as its test vehicle: +6.9 GB of weights, **36 export entries**, ~95 minutes per pod cycle. Nothing +about the mint MACHINERY needs any of that. This family runs the identical +machinery over a 1.1 MB generated checkpoint with **3 export entries**, so a +change to the mint path can be proven in minutes instead of hours. + +It is a real org worker, not a fixture: its own `pyproject.toml`, +`endpoint.toml`, Dockerfile-first build contract, catalog slot, registered +export declaration, and two served arms. The only thing about it that is small +is the model. + +``` +src/micro_diffusion/ + model.py MicroDenoiser (tiny DiT) + MicroDecoder — conv-free, register_buffer table + weights.py deterministic seed -> checkpoint; `python -m micro_diffusion.weights` + pipeline.py MicroPipeline: .denoiser / .decoder, from_pretrained + aot_declaration.py the Compile declaration — 3 entries, container inputs + main.py @endpoint Generate: generate (cfg on) / generate_turbo (cfg off) +``` + +## The three entries, and why exactly three + +``` +denoiser/cfg=true the guided arm; container arity 2 +denoiser/cfg=false the turbo arm; container arity 1 +decoder a SECOND target, its own dims, no fork +``` + +That set is the smallest one that still exercises every decision the mint path +makes: plan selection, a fork coordinate, a **derived dynamic range** (two +latent rows collapse into one artifact per arm), a second target, entry naming, +the seal, the publish wire, and the cross-process adopt filter. + +Two declared facts are there specifically to keep a known defect class under +test on every cycle: + +* **A container input with a plain input immediately after it.** `x` is a + python `list[Tensor]` of arity N, `t` is a plain `(N,)` tensor, `cond` is a + second list. When `x` expands to N leaves, every contract position after it + shifts — which is exactly the divergence pgw#994 fixed (`input_contract` + records the FLATTENED position; `bind_call_inputs` was matching it against + the caller's PRE-flattening args). Any regression binds the whole list to + element 0 and the parity leg goes red in seconds. +* **One dim carried by both a container element axis and a plain tensor axis.** + `H_lat` is `("x", 1)` for the denoiser and `("latent", 2)` for the decoder. + That is pgw#993's seam: `carried_by` has to resolve through the same + expansion `dynamic_shapes` mirrors. + +## Weights: generated, never fetched + +There is no checkpoint in git, none on a developer's box, and no download at +boot. `micro_diffusion.weights` maps `(seed, config) -> bytes` deterministically +and materializes the tree wherever it is needed — into the image at +`docker build` time, on the pod at boot if the binding resolved to an empty +tree, or into the local rig's scratch root. + +```bash +python -m micro_diffusion.weights --out /tmp/w --verify # 1.1 MB, reproduces from seed 997 +``` + +`--verify` regenerates every tensor and byte-compares. The Dockerfile runs it +with `--verify`, so an image whose weights did not reproduce fails the build +rather than shipping a checkpoint nobody else can rebuild. + +## Local: the full cycle, in the rig + +The pgw#978 micro-mint rig drives the whole production mint path against this +package on this box — no pod, no RunPod, no hub. + +```bash +task rig:micro # the full cycle against micro-diffusion +task rig:mint -- --vehicle micro # same thing, long form +task rig:mint # pgw#978's original one-entry plumbing toy +``` + +Legs: gates → weights → handoff → mint-child (a REAL spawned interpreter doing +`torch.export` + AOTInductor) → publish (the real `CellPublisher` wire) → +adopt+parity (a SECOND OS process discovering the cell, arming it, and +comparing every arm against eager). + +--- + +# ⛔ POD RUNBOOK — **DO NOT RUN WITHOUT PAUL'S EXPLICIT GO** + +Nothing below has been executed. It is written so that when the go comes, the +run is a transcription rather than a design session. Every step is the same +step attempt 26's sdxl runbook uses; only the sizes differ. **Timings marked +ESTIMATE are derived, not measured** — measuring them is the first cycle's job. + +Preconditions (all verified before step 1, none assumed): + +- `task inflight STACK=dev` clean, 0 pods live, `max_concurrent_boots` is 1 + fleet-wide so one `booting` row anywhere blocks this. +- The hub's `platform_discretionary_budget` has headroom (a cell mint is + platform-paid work). +- The wheel is a version that has completed a local `task rig:micro` cycle. + A wheel nothing has proven locally is what this whole family exists to stop. + +### 1. Wheel — pin the endpoint at the version under test + +`gen-worker==` in `pyproject.toml`, `uv lock`, tar the directory. +`endpoint.toml` is KEPT (it carries the real build profile). +**ESTIMATE: < 1 min.** No commit to `inference-endpoints` is wanted — this is a +proof artifact, not a fleet pin. + +> ⚠️ **The pin must carry pgw#994 (`2165c2d5`) — 0.93.4 or a master build.** +> This family declares a container input with a plain input after it, which is +> exactly the shape whose contract positions pgw#994 fixed. On 0.93.3 the cell +> mints and seals and then **refuses at ingress on its first served call**, so +> the run would burn a pod to rediscover a fixed defect. The local rig runs +> against master and its parity leg is a green proof of that fix. + +### 2. Create the endpoint (first time only) + +``` +POST /api/v1/endpoints {"owner":"tensorhub","name":"micro-diffusion"} +``` + +Auth: `POST /api/v1/password/login` → **`access_token`** (not `access`), +15-minute expiry — refresh it around the build. + +### 3. Publish the release + +``` +POST /api/v1/endpoints/tensorhub/micro-diffusion/releases?dev=true&skip_profiling=true +Content-Type: application/gzip (raw tarball body) +``` + +202 → `{build_id, proposed_release_id}`; `200 {"status":"noop"}` is also +success. Poll `GET /api/v1/endpoint-builds/{id}` to `succeeded`. +**ESTIMATE: 2-3 min** (sdxl's measured build is 4m30s; this image installs no +diffusers/transformers/accelerate and its weight-generation layer is ~1 s, so +the delta is the dependency install). + +### 4. Tag `prod` — BEFORE the buy + +``` +PUT /api/v1/endpoints/tensorhub/micro-diffusion/tags/prod {"release_id": …} +``` + +`compile-cells` reads the orchestrator's in-memory `LoadRelease` cache and +answers `409 no_compile_declaration` for a release the runtime has not loaded. +That 409 has twice been misread as a missing declaration; it is a cold cache. +**ESTIMATE: seconds.** + +### 5. Arm mint boots + +`TENSORHUB_COMPILE_OBLIGATION_MINT_BOOTS=true`, restart the hub **process +alone**. Confirm from the LOG, not the API: +`[cell-obligation] loop started mint_boots=true`. The `"armed"` field in the +`compile-cells` 202 reads current config, not the running loop's snapshot, and +will lie to you. **ESTIMATE: < 1 min.** + +### 6. Buy + +``` +POST /v1/admin/compile-cells {"release_id":…, "gpu_model":"L40S", "coverage":"warmup"} +``` + +Required, not optional: micro-diffusion is not a flagship family, so a +publish-seeded obligation is `tier=lazy` and is never bought. The same call +un-parks (its `ON CONFLICT (release_id, sku) DO UPDATE` resets `status`, +`attempts`, `discharged_at`, `not_before`). **Buy it as FORGE** — 12 h worker +JWT instead of 30 min, plus the activity-backstop and idle-turnover exemptions. + +### 7. Watch + +``` +GET /v1/admin/mints?release=… +GET /v1/admin/worker-activity-events?kind=aot_mint_phases&release=… +GET /v1/admin/fleet-status | .compile_cells +``` + +**ESTIMATE: 3-5 min pod-side**, decomposed rather than guessed: + +| phase | sdxl (measured) | micro (ESTIMATE) | why | +|---|---|---|---| +| pod boot + image pull | ~2 min | ~1-2 min | much smaller image | +| weights download | minutes (6.9 GB) | **0 s** | generated into the image | +| load + warm | ~1 min | seconds | 1.1 MB, 2 steps | +| export + AOTI compile | ~90 min / 36 entries | ~2-3 min / 3 entries | 12x fewer entries, tiny graphs | +| seal + publish | ~1 min | seconds | the cell is small | + +### 8. Adopt + +Drive demand so a SECOND pod boots cold and adopts the published cell from the +hub. Bank the eager arm on a pod that is NOT concurrently minting. + +### 9. Safety half + +The mint is sm_89 (L40S). Boot an `a100-sxm4-80gb` (sm_80) and record the TYPED +refusal — an untested refusal is not a guarantee. + +**Whole-cycle ESTIMATE: 5-8 minutes**, against sdxl's measured ~95. That +number is the deliverable; the first real run replaces every ESTIMATE above +with a measurement. diff --git a/examples/micro-diffusion/endpoint.toml b/examples/micro-diffusion/endpoint.toml new file mode 100644 index 00000000..6cab12e8 --- /dev/null +++ b/examples/micro-diffusion/endpoint.toml @@ -0,0 +1,16 @@ +schema_version = 1 +name = "micro-diffusion" +main = "micro_diffusion.main" + +[runtime] +language = "python" + +# One profile, matching the fleet's current cuda/python/torch tuple, so a cell +# minted here is adoptable by the same pool every other family serves from. +# The image is small because the package pulls no diffusers/transformers. +[[build.profiles]] +name = "default" +accelerator = "cuda" +cuda = "13.0" +python = "3.12" +torch = "2.13.0" diff --git a/examples/micro-diffusion/pyproject.toml b/examples/micro-diffusion/pyproject.toml new file mode 100644 index 00000000..d6bd3705 --- /dev/null +++ b/examples/micro-diffusion/pyproject.toml @@ -0,0 +1,51 @@ +[project] +name = "micro-diffusion" +version = "0.1.0" +description = "The fleet's smallest REAL endpoint family — three export entries over a deterministically generated toy checkpoint, so a full AOT mint cycle costs minutes" +requires-python = ">=3.12,<3.13" +dependencies = [ + # Hard-pinned per th#1098 fleet policy: compile cells verify() EXACT on + # the gen-worker version, so a range would make an adopted cell's identity + # depend on what the build happened to resolve. + # + # ⚠️ THIS FAMILY'S SERVE PATH REQUIRES pgw#994. It declares a `repeat=` + # container input with a plain input after it, which is precisely the + # shape whose contract positions pgw#994 fixed. On 0.93.3 the cell MINTS + # and SEALS and then refuses at ingress on its first served call — the + # same failure z-image's tracker entry describes. Bump this to the first + # release carrying `2165c2d5` (0.93.4, or a master build) before any pod + # run; the local rig already runs against master and its parity leg is + # currently a green proof of that fix. + "gen-worker==0.93.3", + "msgspec>=0.18", + "safetensors>=0.4", + "pillow", +] + +# NO diffusers, NO transformers, NO accelerate. The whole point of this family +# is that its image is small and its boot is short; a dependency it does not +# use would cost both on every cycle. + +[dependency-groups] +local = [ + "torch>=2.11.0", +] +dev = [ + "mypy>=1.10.0", + "pytest>=9.0.3", +] + +[tool.gen_worker] +main = "micro_diffusion.main" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src/micro_diffusion"] + +[tool.mypy] +python_version = "3.12" +ignore_missing_imports = true +disallow_untyped_defs = true diff --git a/examples/micro-diffusion/src/micro_diffusion/__init__.py b/examples/micro-diffusion/src/micro_diffusion/__init__.py new file mode 100644 index 00000000..695edc49 --- /dev/null +++ b/examples/micro-diffusion/src/micro_diffusion/__init__.py @@ -0,0 +1,22 @@ +"""micro-diffusion — the fleet's smallest REAL endpoint family. + +Its reason to exist is cycle time: a full production-path AOT mint against +sdxl is 36 export entries and ~95 minutes on a pod, which makes every mint +change a multi-hour experiment. This family declares THREE entries over a +generated toy checkpoint and runs the identical machinery. +""" + +from .aot_declaration import DECLARATION, FAMILY +from .main import Generate, MicroDefaults, MicroIn, MicroOut, Size +from .pipeline import MicroPipeline + +__all__ = [ + "DECLARATION", + "FAMILY", + "Generate", + "MicroDefaults", + "MicroIn", + "MicroOut", + "MicroPipeline", + "Size", +] diff --git a/examples/micro-diffusion/src/micro_diffusion/aot_declaration.py b/examples/micro-diffusion/src/micro_diffusion/aot_declaration.py new file mode 100644 index 00000000..e77e0141 --- /dev/null +++ b/examples/micro-diffusion/src/micro_diffusion/aot_declaration.py @@ -0,0 +1,167 @@ +"""The micro family's export declaration — THREE entries, on purpose. + +sdxl declares 36 (10 aspect rows x static-rows x targets) and a mint cycle +against it costs ~95 minutes on a pod. Nothing about the MACHINERY needs 36: +the mint path's decisions — plan selection, container flattening, the derived +dynamic range, the fork coordinate, the seal, the publish wire, the adopt +filter — are all exercised by three. This declaration is the smallest set that +still exercises every one of them. + +The three entries +----------------- + + denoiser/cfg=true the guided arm; the container arity is 2 + denoiser/cfg=false the turbo arm; the container arity is 1 + decoder one arm, no fork, its own dims + +Why each declared fact is what it is +------------------------------------ + +* ``shape_strategy="dynamic-collapse"`` — legitimate here rather than + convenient: #730 ratified the strategy for conv-free graphs, and + :mod:`micro_diffusion.model` contains zero ``nn.Conv*`` layers by + construction. It is also the strategy that makes the two declared latent + rows COLLAPSE into one artifact per arm instead of multiplying entries, + which is the difference between 3 entries and 6. + +* ``cfg`` is a FORK, not a dim. The pipeline batches CFG into ONE forward by + building a two-element list, so the pytree ARITY changes and N=1 / N=2 are + two graphs rather than one graph at two sizes. That is z-image's measured + shape and it is why the container inputs exist at all. + +* ``T`` (the token count) is carried by BOTH a container element axis + (``("x", 0)`` — the axis of a list ELEMENT) and a plain tensor axis + (``("latent", 1)``). One dim, two carriers, two flattening regimes: that is + precisely the seam pgw#993 fixed on the declaration side (``carried_by`` + must resolve through the same expansion ``dynamic_shapes`` mirrors) and + pgw#994 on the serve side (a contract position among FLATTENED leaves, + replayed against a caller's PRE-flattening args). + +* The compiled targets take TOKEN SEQUENCES, not latent grids, so the one + dynamic extent is LINEAR in a single symbol. That is flux/qwen's real + interface, and it is also forced: with H and W both dynamic every matmul's + M extent is a PRODUCT of two symbols, and the mint's + ``torch.export.save``/``load`` hand-off to its compile child loses the + facts inductor needs to lower one (pgw#998, found by the rig's first + micro cycle). + +* ``t`` is a PLAIN input declared immediately AFTER a container input. That + ordering is deliberate and is the cheapest possible reproduction of the + pgw#994 defect shape: with ``x`` expanding to N leaves, every leaf position + after it shifts, so a serve side that matched contract positions against + pre-flattening args binds the whole list to element 0 and shifts ``t`` and + ``cond``. Every micro cycle re-proves that it does not. + +* ``warm_changes_key=False`` — MEASURED, not defaulted. The model builds no + tables lazily: the one table it has is a registered buffer created in + ``__init__``, so a pre-warmed export and a cold export trace the same graph. + (z-image's True comes from ``RopeEmbedder`` building its rope tables inside + the first ``__call__``.) +""" + +from __future__ import annotations + +from gen_worker import ( + Compile, + Dim, + Fork, + GraphClass, + Input, + register_export_declaration, +) + +FAMILY = "micro-diffusion" + +#: The two latent grids the family serves, and the pixel rows they are. +#: Two, not one: a single row would leave ``dynamic-collapse`` with nothing to +#: collapse and the export fully static, which is the one path where the +#: pgw#993 dynamic-shapes mirroring never runs. +LATENT_ROWS = (32, 48) +VAE_SCALE = 8 +PIXEL_ROWS = tuple((n * VAE_SCALE, n * VAE_SCALE) for n in LATENT_ROWS) + +#: The TOKEN count each latent grid becomes. The compiled targets take token +#: sequences, so the one dynamic extent is linear in a single symbol — see +#: pgw#998 for what a nonlinear extent costs across the mint's export +#: save/load hand-off. +TOKEN_ROWS = tuple(n * n for n in LATENT_ROWS) + +#: The pinned condition length (the ie#544 axis: declared, never discovered). +COND_LEN = 16 + +#: The CFG batch. Two on the guided arm. +CFG_ARITY = 2 + + +def _classes() -> tuple: + rows = [] + for tokens in TOKEN_ROWS: + for cfg, arity in ((True, CFG_ARITY), (False, 1)): + rows.append(GraphClass( + dims={"N": arity, "T": tokens}, + fork={"cfg": cfg}, targets=("denoiser",))) + rows.append(GraphClass( + dims={"N": 1, "T": tokens}, targets=("decoder",))) + return tuple(dict.fromkeys(rows)) + + +def build_declaration() -> Compile: + """Construct and validate the declaration without registering it.""" + return Compile( + family=FAMILY, + targets=("denoiser", "decoder"), + shapes=PIXEL_ROWS, + text_len=COND_LEN, + dims=( + # N is the container ARITY and, simultaneously, the only axis of + # `t` — which is what makes it nameable. A list length has no + # (input, axis) binding of its own to give. + Dim("N", carried_by=(("t", 0), ("latent", 0))), + # `x` elements are (T, C) -> element axis 0. + # `latent` is a plain (N, T, C) tensor -> axis 1. + # ONE dim, one carrier INSIDE a container and one outside it. + Dim("T", carried_by=(("x", 0), ("latent", 1))), + ), + forks=( + Fork("cfg", served=(True, False), targets=("denoiser",), + why="the pipeline batches classifier-free guidance into ONE " + "forward by building a two-element latent list, so the " + "pytree ARITY doubles: N=1 and N=2 are two graphs, not " + "one graph at two sizes. The turbo lane pins guidance to " + "0.0 and takes the arity-1 branch."), + ), + classes=_classes(), + inputs=( + # CONTAINER, then a PLAIN input, then a CONTAINER again — the + # ordering that makes flattened leaf positions diverge from + # argument positions (pgw#993/pgw#994). + Input("x", shape=("T", ("config", "in_channels")), + repeat="N", dtype="float32", targets=("denoiser",)), + Input("t", shape=("N",), dtype="float32", targets=("denoiser",)), + Input("cond", shape=(COND_LEN, ("config", "cond_dim")), + repeat="N", dtype="float32", targets=("denoiser",)), + Input("latent", shape=("N", "T", ("config", "in_channels")), + dtype="float32", targets=("decoder",)), + ), + args=(), + shape_strategy="dynamic-collapse", + warm_changes_key=False, + ) + + +DECLARATION = build_declaration() + +register_export_declaration(DECLARATION, replace=True) + + +__all__ = [ + "CFG_ARITY", + "COND_LEN", + "DECLARATION", + "FAMILY", + "LATENT_ROWS", + "PIXEL_ROWS", + "TOKEN_ROWS", + "VAE_SCALE", + "build_declaration", +] diff --git a/examples/micro-diffusion/src/micro_diffusion/main.py b/examples/micro-diffusion/src/micro_diffusion/main.py new file mode 100644 index 00000000..c2ff0ddf --- /dev/null +++ b/examples/micro-diffusion/src/micro_diffusion/main.py @@ -0,0 +1,169 @@ +"""The micro-diffusion worker function — a REAL org worker, deliberately small. + +It exists so that a full production-path AOT mint cycle costs minutes instead +of the ~95 that sdxl's 36 entries cost on a pod. Everything about its SHAPE is +production: a catalog slot with no code default, a declaration registered at +import, two served arms that map onto the two declared fork coordinates, and a +Dockerfile-first build. The only thing that is small is the model. + +Two shapes here are load-bearing and neither is incidental: + +**The slot is a CATALOG slot** — ``Slot(MicroPipeline, selected_by="model")`` +with no ``default_checkpoint=``. That is sdxl's shape and it is the shape +pgw#969 died on: the mint child re-runs discovery in a fresh interpreter, so a +catalog slot rediscovers NOTHING and ``ctx.slots["pipeline"]`` raises unless +the parent's ``MintSlot`` crossed the delegation boundary intact. + +**The handler dereferences ``ctx.slots`` first.** That is the exact call that +crashed 0.0 s into ``warmup_forward`` on two L40S pods. +""" + +from __future__ import annotations + +from typing import List + +import msgspec +import torch + +from gen_worker import ( + Compile, + RequestContext, + Resources, + Slot, + StringEnum, + endpoint, +) +from gen_worker.families import GenerationDefaults, family + +from .aot_declaration import ( # noqa: F401 — registers at import, as a real endpoint does + CFG_ARITY, + COND_LEN, + DECLARATION, + FAMILY, + LATENT_ROWS, + PIXEL_ROWS, + TOKEN_ROWS, + VAE_SCALE, +) +from .pipeline import MicroPipeline + + +class Size(StringEnum): + """The served latent rows, as the payload's legality oracle (pgw#669). + + A bare width/height int would be a free shape-affecting field — the thing + every fleet endpoint is linted against — so the rows are an enum and the + latent math lives in the declaration, once. + """ + + SMALL = "256x256" + LARGE = "384x384" + + +_LATENT_BY_SIZE = { + Size.SMALL: LATENT_ROWS[0], + Size.LARGE: LATENT_ROWS[1], +} + + +@family(FAMILY) +class MicroDefaults(GenerationDefaults, frozen=True): + steps: int = 2 + guidance: float = 4.0 + + +class MicroIn(msgspec.Struct): + prompt: str = "" + size: Size = Size.SMALL + #: ``selected_by="model"`` binds the catalog slot off this field. + model: str = "" + + +class MicroOut(msgspec.Struct): + #: The saved image, or "" on the boot warm pass (which saves nothing). + image: str = "" + #: Which checkpoint actually served, read off the resolved slot — so a + #: cycle can PROVE which bytes were traced rather than trusting that some + #: were. + checkpoint: str = "" + shape: str = "" + + +@endpoint( + models={"pipeline": Slot(MicroPipeline, selected_by="model")}, + compile=Compile( + family=FAMILY, targets=("denoiser", "decoder"), shapes=PIXEL_ROWS, + text_len=COND_LEN), + resources=Resources(gpu=True), +) +class Generate: + def setup(self, pipeline: MicroPipeline) -> None: + self.pipe = pipeline + + def generate(self, ctx: RequestContext[MicroDefaults], data: MicroIn) -> MicroOut: + """The guided arm — ``cfg=true``, container arity 2.""" + return self._run(ctx, data, arity=CFG_ARITY, + guidance=ctx.defaults.guidance) + + def generate_turbo( + self, ctx: RequestContext[MicroDefaults], data: MicroIn, + ) -> MicroOut: + """The turbo arm — guidance pinned to 0.0, so ``cfg=false`` and the + container arity is 1. A separate METHOD rather than a flag, because + the two arms are two traced graphs.""" + return self._run(ctx, data, arity=1, guidance=0.0) + + def _run( + self, ctx: RequestContext[MicroDefaults], data: MicroIn, *, + arity: int, guidance: float, + ) -> MicroOut: + resolved = ctx.slots["pipeline"] + grid = _LATENT_BY_SIZE[Size(data.size)] + device = self.pipe.device + config = self.pipe.config + generator = ctx.generator(abs(hash(data.prompt)) % (2 ** 31)) + # Token sequences, not latent grids: patchify is the PIPELINE's job + # here, the way it is in flux and qwen. + latents: List[torch.Tensor] = [ + torch.randn(grid * grid, config.in_channels, + generator=generator, device=device, dtype=torch.float32) + for _ in range(arity) + ] + cond: List[torch.Tensor] = [ + torch.randn(COND_LEN, config.cond_dim, generator=generator, + device=device, dtype=torch.float32) + for _ in range(arity) + ] + steps = 1 if ctx.boot_warmup else ctx.defaults.steps + pixels = self.pipe(latents, cond, grid=grid, steps=steps, + guidance=guidance) + out = MicroOut( + checkpoint=str(resolved.ref.path), + shape=str(tuple(int(n) for n in pixels.shape))) + if ctx.boot_warmup: + # The warm pass proves the GRAPH, not the encoder. Saving here + # would put an image encode on the boot critical path for nothing. + return out + out.image = ctx.save_image(_to_image(pixels[0])).ref + return out + + +def _to_image(pixels: torch.Tensor) -> object: + from PIL import Image + + array = ((pixels.detach().float().clamp(-1, 1) + 1) * 127.5) + array = array.permute(1, 2, 0).to(torch.uint8).cpu().numpy() + return Image.fromarray(array) + + +__all__ = [ + "DECLARATION", + "TOKEN_ROWS", + "FAMILY", + "VAE_SCALE", + "Generate", + "MicroDefaults", + "MicroIn", + "MicroOut", + "Size", +] diff --git a/examples/micro-diffusion/src/micro_diffusion/model.py b/examples/micro-diffusion/src/micro_diffusion/model.py new file mode 100644 index 00000000..2f612eae --- /dev/null +++ b/examples/micro-diffusion/src/micro_diffusion/model.py @@ -0,0 +1,200 @@ +"""The micro family's two compile targets: a tiny DiT and a tiny decoder. + +Shaped like the thing the fleet mints, sized so a whole mint is seconds. + +Deliberate structural choices, each with a reason the mint can read: + +* **No ``nn.Conv*`` anywhere.** #730 ratified ``dynamic-collapse`` for + conv-free graphs and ``static-rows`` for conv-bearing ones — its 6.9% AOTI + gap was root-caused as inductor's channels-last layout opt bailing when a + convolution carries a free symbol. A conv here would force the declaration + onto ``static-rows``, which is the strategy that makes sdxl 36 entries. + Conv-free is what buys the 3-entry declaration. +* **The denoiser takes a python ``list`` of latents**, z-image's real shape: + CFG is batched by concatenating the list, so the pytree ARITY doubles and + N=1/N=2 are two graphs. This is what puts a CONTAINER input, and a plain + input immediately AFTER it, in every mint cycle — pgw#993 (declaration-side + flattening) and pgw#994 (serve-side binding) both live on that seam. +* **The rope table is a registered buffer** (pgw#857): a plain attribute is + lifted by ``torch.export`` as an anonymous ``_tensor_constant`` literal + whose bytes then ship inside every compiled cell instead of staying a + deduplicated weight. +""" + +from __future__ import annotations + +import math +from typing import List + +import torch +from torch import nn + + +class MicroConfig: + """The config object the export declaration reads widths off. + + A plain attribute holder rather than a dataclass: declaration files are + exec'd by path without a ``sys.modules`` entry, and ``@dataclass`` + resolves annotations through ``sys.modules[cls.__module__].__dict__``. + """ + + __slots__ = ("in_channels", "cond_dim", "cond_len", "hidden", "depth", + "vae_scale", "seed") + + def __init__( + self, + in_channels: int = 4, + cond_dim: int = 32, + cond_len: int = 16, + hidden: int = 128, + depth: int = 2, + vae_scale: int = 8, + seed: int = 997, + ) -> None: + self.in_channels = int(in_channels) + self.cond_dim = int(cond_dim) + self.cond_len = int(cond_len) + self.hidden = int(hidden) + self.depth = int(depth) + self.vae_scale = int(vae_scale) + self.seed = int(seed) + + def as_dict(self) -> dict: + return {name: getattr(self, name) for name in self.__slots__} + + +class _TimestepEmbedding(nn.Module): + """Sinusoidal features -> two Linears; the usual shape at toy width.""" + + def __init__(self, hidden: int) -> None: + super().__init__() + self.hidden = hidden + self.lin1 = nn.Linear(hidden, hidden) + self.lin2 = nn.Linear(hidden, hidden) + half = hidden // 2 + # pgw#857: a table, not a learned parameter, and therefore a BUFFER. + # As a plain attribute torch.export would lift it as a literal and its + # bytes would ship inside the cell. + self.register_buffer( + "freqs", + torch.exp(-torch.arange(half, dtype=torch.float32) + * (math.log(10000.0) / max(1, half - 1))), + persistent=False) + + def forward(self, t: torch.Tensor) -> torch.Tensor: + angles = t.float()[:, None] * self.freqs[None, :] + feats = torch.cat([torch.sin(angles), torch.cos(angles)], dim=-1) + return self.lin2(torch.nn.functional.silu(self.lin1(feats))) + + +class _CrossAttention(nn.Module): + """Single-head cross attention from the token grid onto the condition.""" + + def __init__(self, hidden: int, cond_dim: int) -> None: + super().__init__() + self.scale = hidden ** -0.5 + self.norm = nn.LayerNorm(hidden) + self.to_q = nn.Linear(hidden, hidden, bias=False) + self.to_k = nn.Linear(cond_dim, hidden, bias=False) + self.to_v = nn.Linear(cond_dim, hidden, bias=False) + self.to_out = nn.Linear(hidden, hidden) + + def forward(self, x: torch.Tensor, cond: torch.Tensor) -> torch.Tensor: + q = self.to_q(self.norm(x)) + k = self.to_k(cond) + v = self.to_v(cond) + attn = torch.softmax((q @ k.transpose(-1, -2)) * self.scale, dim=-1) + return x + self.to_out(attn @ v) + + +class _Block(nn.Module): + def __init__(self, hidden: int, cond_dim: int) -> None: + super().__init__() + self.attn = _CrossAttention(hidden, cond_dim) + self.norm = nn.LayerNorm(hidden) + self.mlp_in = nn.Linear(hidden, hidden * 2) + self.mlp_out = nn.Linear(hidden * 2, hidden) + + def forward(self, x: torch.Tensor, cond: torch.Tensor) -> torch.Tensor: + x = self.attn(x, cond) + h = self.mlp_out(torch.nn.functional.gelu(self.mlp_in(self.norm(x)))) + return x + h + + +class MicroDenoiser(nn.Module): + """The compile target ``denoiser``. + + ``forward(x, t, cond)`` where ``x`` and ``cond`` are python LISTS of + length N and ``t`` is a plain ``(N,)`` tensor sitting between them. + That ordering is the point: it is the exact arrangement whose flattened + leaf positions diverge from its pre-flattening argument positions. + + ``x`` elements are TOKEN SEQUENCES ``(T, C)``, not latent grids + ``(C, H, W)``. That is flux/qwen's real interface — patchify and + unpatchify live in the pipeline — and it is also forced: a grid whose H + and W are both dynamic makes every matmul's M extent a PRODUCT of two + symbols, and the mint's ``torch.export.save``/``load`` hand-off to its + compile child loses the facts inductor needs to lower a nonlinear size. + Measured by the micro-mint rig on torch 2.13.0+cu130: + ``LoweringException: RuntimeError: ('unexpected None!', 512*s18*s57)``, + where the identical graph compiles fine WITHOUT the round trip. Filed as + pgw#998; a linear token extent sidesteps it entirely. + """ + + def __init__(self, config: MicroConfig) -> None: + super().__init__() + self.config = config + hidden = config.hidden + self.proj_in = nn.Linear(config.in_channels, hidden) + self.time_embed = _TimestepEmbedding(hidden) + self.blocks = nn.ModuleList( + [_Block(hidden, config.cond_dim) for _ in range(config.depth)]) + self.norm_out = nn.LayerNorm(hidden) + self.proj_out = nn.Linear(hidden, config.in_channels) + + def forward( + self, + x: List[torch.Tensor], + t: torch.Tensor, + cond: List[torch.Tensor], + ) -> torch.Tensor: + temb = self.time_embed(t) + outs: List[torch.Tensor] = [] + # Python-level iteration over the container: export UNROLLS it, the + # way z-image's `for image, cap_feat in zip(...)` unrolls. Nothing + # here reads a tensor VALUE, so there is no data-dependent branch. + for i, tokens in enumerate(x): + h = self.proj_in(tokens) + temb[i][None, :] + for block in self.blocks: + h = block(h, cond[i]) + outs.append(self.proj_out(self.norm_out(h))) + return torch.stack(outs, dim=0) + + +class MicroDecoder(nn.Module): + """The compile target ``decoder``: latent tokens -> pixel CELLS. + + ``(N, T, C) -> (N, T, 3 * scale * scale)``: one ``scale x scale`` RGB cell + per latent token. The pixel-shuffle that turns those cells into an image + is the pipeline's job, not this module's — the same division real + pipelines make, where the transformer never sees the image layout. + + Conv-free on purpose (#730 ratified ``dynamic-collapse`` for conv-free + graphs), and token-shaped for the same reason the denoiser is: every + extent stays LINEAR in one symbol. + """ + + def __init__(self, config: MicroConfig) -> None: + super().__init__() + self.config = config + scale = config.vae_scale + self.proj_in = nn.Linear(config.in_channels, config.hidden) + self.norm = nn.LayerNorm(config.hidden) + self.proj_out = nn.Linear(config.hidden, 3 * scale * scale) + + def forward(self, latent: torch.Tensor) -> torch.Tensor: + h = torch.nn.functional.silu(self.proj_in(latent)) + return torch.tanh(self.proj_out(self.norm(h))) + + +__all__ = ["MicroConfig", "MicroDecoder", "MicroDenoiser"] diff --git a/examples/micro-diffusion/src/micro_diffusion/pipeline.py b/examples/micro-diffusion/src/micro_diffusion/pipeline.py new file mode 100644 index 00000000..1702e64f --- /dev/null +++ b/examples/micro-diffusion/src/micro_diffusion/pipeline.py @@ -0,0 +1,105 @@ +"""The diffusers-SHAPED holder the slot resolves to. + +``.denoiser`` and ``.decoder`` are the two compile targets; ``from_pretrained`` +is the contract the SDK's slot loader calls and it reads only from the local +tree it is handed. If that tree does not exist yet it is GENERATED, never +fetched — see :mod:`micro_diffusion.weights`. +""" + +from __future__ import annotations + +from pathlib import Path +from typing import Any, List, Optional + +import torch + +from .model import MicroConfig, MicroDecoder, MicroDenoiser +from .weights import SEED, load_config, load_state, materialize + + +class MicroPipeline: + def __init__( + self, denoiser: MicroDenoiser, decoder: MicroDecoder, source: str = "", + ) -> None: + self.denoiser = denoiser + self.decoder = decoder + self.source = source + self.config = denoiser.config + + @classmethod + def from_pretrained(cls, path: str, **_kw: Any) -> "MicroPipeline": + root = Path(path) + if not (root / "config.json").is_file(): + # A pod whose binding resolved to an empty dir, or a boot before + # the build step ran. Generating is CHEAPER than failing and is + # the family's whole premise, so do it and say where. + materialize(root, seed=SEED) + config = load_config(root) + state = load_state(root) + denoiser = MicroDenoiser(config) + decoder = MicroDecoder(config) + denoiser.load_state_dict( + {k[len("denoiser."):]: v for k, v in state.items() + if k.startswith("denoiser.")}, strict=False) + decoder.load_state_dict( + {k[len("decoder."):]: v for k, v in state.items() + if k.startswith("decoder.")}, strict=False) + return cls(denoiser.eval(), decoder.eval(), source=str(root)) + + def to(self, device: Any) -> "MicroPipeline": + self.denoiser.to(device) + self.decoder.to(device) + return self + + @property + def device(self) -> torch.device: + return next(self.denoiser.parameters()).device + + def unpatchify(self, cells: torch.Tensor, grid: int) -> torch.Tensor: + """``(N, T, 3*s*s) -> (N, 3, grid*s, grid*s)``. + + In the PIPELINE, not in the decoder: the compiled targets take token + sequences so every traced extent stays linear in one symbol, and the + image layout is recovered outside the graph. That is the same + division flux and qwen make. + """ + scale = self.config.vae_scale + batch = cells.shape[0] + out = cells.reshape(batch, grid, grid, scale, scale, 3) + out = out.permute(0, 5, 1, 3, 2, 4) + return out.reshape(batch, 3, grid * scale, grid * scale) + + def __call__( + self, + latents: List[torch.Tensor], + cond: List[torch.Tensor], + *, + grid: int, + steps: int = 2, + guidance: float = 4.0, + generator: Optional[torch.Generator] = None, + ) -> torch.Tensor: + """A two-step Euler-ish loop with the fleet's real CFG shape. + + ``len(latents)`` IS the fork coordinate: 2 on the guided arm (the + conditional and unconditional rows batched into ONE forward, the way + z-image's ``latents.repeat(2,1,1,1)`` does), 1 on the turbo arm. + """ + x = list(latents) + for i in reversed(range(max(1, steps))): + t = torch.full((len(x),), float(i * 100), device=x[0].device) + with torch.no_grad(): + eps = self.denoiser(x, t, cond) + if len(x) == 2: + uncond, text = eps[0], eps[1] + guided = uncond + guidance * (text - uncond) + step = torch.stack([guided, guided], dim=0) + else: + step = eps + x = [x[j] - step[j] / max(1, steps) for j in range(len(x))] + with torch.no_grad(): + cells = self.decoder(x[-1][None, ...]) + return self.unpatchify(cells, grid) + + +__all__ = ["MicroConfig", "MicroPipeline"] diff --git a/examples/micro-diffusion/src/micro_diffusion/weights.py b/examples/micro-diffusion/src/micro_diffusion/weights.py new file mode 100644 index 00000000..6ed8eb7f --- /dev/null +++ b/examples/micro-diffusion/src/micro_diffusion/weights.py @@ -0,0 +1,139 @@ +"""Deterministic weight GENERATION — the micro family never downloads bytes. + +The weights-locality rule says model weights never transit the developer's +box. A micro endpoint that shipped a checkpoint would either violate that or +need a hub round trip on every cycle, so it has neither: the checkpoint is a +pure function of ``(seed, config)`` and is materialized wherever it is needed — +in the image at ``docker build`` time, on the pod at boot, or in the local rig. + +Two runs with the same seed produce BYTE-IDENTICAL files. That is not a nicety: +the cell key and the snapshot digest are claims about which checkpoint was +traced, and they mean nothing if the same ref resolves to different bytes on +two machines. + + python -m micro_diffusion.weights --out /app/.micro-weights + python -m micro_diffusion.weights --out /tmp/w --seed 997 --verify +""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path +from typing import Dict + +import torch +from safetensors.torch import load_file, save_file + +from .model import MicroConfig, MicroDecoder, MicroDenoiser + +CONFIG_NAME = "config.json" +WEIGHTS_NAME = "micro_diffusion.safetensors" + +#: The one seed the fleet's micro family is defined by. Changing it is a new +#: checkpoint, not a new build of the same one. +SEED = 997 + +#: Refuse to write a tree larger than this. The whole point of the family is +#: that a cycle costs minutes; a checkpoint that grew would take the cycle +#: with it, silently. +MAX_TREE_BYTES = 200 * 1000 * 1000 + + +class WeightsRefused(RuntimeError): + """A named precondition failure while materializing the checkpoint.""" + + +def state_dict(config: MicroConfig, *, seed: int = SEED) -> Dict[str, torch.Tensor]: + """Every tensor of both targets, derived from ``seed`` alone. + + One generator, seeded once, consumed in a fixed module-construction + order — so the mapping (seed, config) -> bytes is total and stable. + """ + torch.manual_seed(int(seed)) + denoiser = MicroDenoiser(config) + decoder = MicroDecoder(config) + out: Dict[str, torch.Tensor] = {} + for prefix, module in (("denoiser", denoiser), ("decoder", decoder)): + for name, tensor in module.state_dict().items(): + out[f"{prefix}.{name}"] = tensor.contiguous() + return out + + +def materialize( + root: Path, *, seed: int = SEED, config: MicroConfig | None = None, +) -> Path: + """Write the checkpoint tree under ``root``; return it. + + Idempotent by CONFIG, not by mtime: a tree whose ``config.json`` already + matches is left alone, so repeated boots and repeated rig cycles do not + re-serialize. + """ + root = Path(root) + cfg = config or MicroConfig(seed=seed) + payload = dict(cfg.as_dict(), _class_name="MicroPipeline", + _format="safetensors", seed=int(seed)) + cfg_path = root / CONFIG_NAME + if cfg_path.is_file() and (root / WEIGHTS_NAME).is_file(): + try: + if json.loads(cfg_path.read_text()) == payload: + return root + except ValueError: + pass + root.mkdir(parents=True, exist_ok=True) + save_file(state_dict(cfg, seed=seed), str(root / WEIGHTS_NAME)) + cfg_path.write_text(json.dumps(payload, indent=2, sort_keys=True)) + size = tree_bytes(root) + if size > MAX_TREE_BYTES: + raise WeightsRefused( + f"the generated tree is {size / 1e6:.1f} MB, over the " + f"{MAX_TREE_BYTES / 1e6:.0f} MB ceiling this family exists to stay " + f"under — shrink the config rather than raising the ceiling") + return root + + +def tree_bytes(root: Path) -> int: + return sum(p.stat().st_size for p in Path(root).rglob("*") if p.is_file()) + + +def load_config(root: Path) -> MicroConfig: + raw = json.loads((Path(root) / CONFIG_NAME).read_text()) + fields = set(MicroConfig().as_dict()) + return MicroConfig(**{k: v for k, v in raw.items() if k in fields}) + + +def load_state(root: Path) -> Dict[str, torch.Tensor]: + return load_file(str(Path(root) / WEIGHTS_NAME)) + + +def _verify(root: Path, seed: int) -> int: + """Regenerate into memory and compare — the determinism claim, checked.""" + on_disk = load_state(root) + fresh = state_dict(load_config(root), seed=seed) + if sorted(on_disk) != sorted(fresh): + print("MISMATCH: tensor names differ", file=sys.stderr) + return 1 + for name, tensor in fresh.items(): + if not torch.equal(tensor, on_disk[name]): + print(f"MISMATCH: {name} differs from its regeneration", + file=sys.stderr) + return 1 + print(f"verified {len(fresh)} tensors reproduce from seed={seed}") + return 0 + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(prog="micro_diffusion.weights") + parser.add_argument("--out", type=Path, required=True) + parser.add_argument("--seed", type=int, default=SEED) + parser.add_argument("--verify", action="store_true", + help="regenerate and byte-compare after writing") + args = parser.parse_args(list(argv) if argv is not None else None) + root = materialize(args.out, seed=args.seed) + print(f"{root} — {tree_bytes(root) / 1e6:.2f} MB generated (no download)") + return _verify(root, args.seed) if args.verify else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/micro-diffusion/uv.lock b/examples/micro-diffusion/uv.lock new file mode 100644 index 00000000..1de5321b --- /dev/null +++ b/examples/micro-diffusion/uv.lock @@ -0,0 +1,1132 @@ +version = 1 +revision = 3 +requires-python = "==3.12.*" + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] + +[[package]] +name = "ast-serialize" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/6a/a68c7f823e67714393060a0f232b0d75e0b2d2f1a7aef0633f7007411804/ast_serialize-0.7.0.tar.gz", hash = "sha256:934c0920454381b0beb46a5dc0af114d48699a44537b97282c2346a23990713d", size = 845507, upload-time = "2026-08-06T14:07:38.216Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/d6/4a95e85a3c52f10dba58e15f9c93ef691cf11a076cedf79817afade8d1fb/ast_serialize-0.7.0-cp315-abi3.abi3t-macosx_10_12_x86_64.whl", hash = "sha256:c8c5af5650f2527e758f1fbaaad3deb37c91f1a2d01c7430c63100f51fbb2807", size = 1177734, upload-time = "2026-08-06T14:06:37.17Z" }, + { url = "https://files.pythonhosted.org/packages/a4/9a/c2dca32e435b9c1006f030a65bf487f3bd2e74d38c0e29e1c4deb17ff4cc/ast_serialize-0.7.0-cp315-abi3.abi3t-macosx_11_0_arm64.whl", hash = "sha256:d8ba35d33b1fbd962a7afd835928b1741e90654c81344749b691b92e3aba98e5", size = 1169359, upload-time = "2026-08-06T14:06:39.206Z" }, + { url = "https://files.pythonhosted.org/packages/55/1b/30c73b248905b3de20d1ad11263a5eb5c7d8eec195e5b16e1b30f299225f/ast_serialize-0.7.0-cp315-abi3.abi3t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f858a3f274f20ae65f1dccc9408de10c46a27ebf76eac5708793815f2f36182a", size = 1225641, upload-time = "2026-08-06T14:06:40.915Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ed/9f8d0c17598769fd07a3f57eda6a9f67eff729044067bff0e24ec32643f1/ast_serialize-0.7.0-cp315-abi3.abi3t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db05954e883cc91310493cde193c1c1acbd00ee8ea583f1eff9be9740af50ceb", size = 1227063, upload-time = "2026-08-06T14:06:42.371Z" }, + { url = "https://files.pythonhosted.org/packages/73/28/42309bc14ca149f57320f6808c175689c656f1779ddaa64313dbf079fa38/ast_serialize-0.7.0-cp315-abi3.abi3t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:507f5633ffec9d7cedfd8b90b986c329ceafb9deeaf4cd2bba9782affd83111e", size = 1425301, upload-time = "2026-08-06T14:06:43.891Z" }, + { url = "https://files.pythonhosted.org/packages/4f/75/493961f5deb0b02e688a83b8b9761aed76c8d655519f0cae8388d3ce4082/ast_serialize-0.7.0-cp315-abi3.abi3t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1356c62fd91e73786e5f9b9de71f094c8d850d194f652de8c45ee12690534ee", size = 1245906, upload-time = "2026-08-06T14:06:45.412Z" }, + { url = "https://files.pythonhosted.org/packages/56/9b/98350c0b7530218cf0db629ebc39c23f3c8b45f82d29be415cc5a455bab1/ast_serialize-0.7.0-cp315-abi3.abi3t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eadaedebf5e3bf0d6dfa309c53283737c668a9e04ea39648e3607ee74cfef904", size = 1250047, upload-time = "2026-08-06T14:06:47.027Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3f/c8f2864f3d088bf0e41af2bb52462348a1d6c24c4fd0b4988b17c6594d78/ast_serialize-0.7.0-cp315-abi3.abi3t-manylinux_2_31_riscv64.whl", hash = "sha256:1af0a4509871fd55f15335a5e8f643114c5c5cb485b90fcfa0d8b33861cdcc63", size = 1243423, upload-time = "2026-08-06T14:06:48.571Z" }, + { url = "https://files.pythonhosted.org/packages/71/02/414c98fed866c0b584ef2d294a65561d5eaf5c58e8f23d099ea00f42e529/ast_serialize-0.7.0-cp315-abi3.abi3t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8530f722344889785da4006f663735e470bfb22fd30eea20e89840ba3cb42fa1", size = 1294528, upload-time = "2026-08-06T14:06:50.157Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4f/b6b207f6fcf03b75c01605a16966e0133c3eb40e07c8e3dc66354ee7d550/ast_serialize-0.7.0-cp315-abi3.abi3t-musllinux_1_2_aarch64.whl", hash = "sha256:80a1f859f8f5707848fd92c36daf01d522dbc3f2c066a2d9287e3bec0d79b4ac", size = 1401849, upload-time = "2026-08-06T14:06:52.016Z" }, + { url = "https://files.pythonhosted.org/packages/31/86/676e2b65a919f39b6a04dae6ae863334561e0fbf6d30a403475f94203f35/ast_serialize-0.7.0-cp315-abi3.abi3t-musllinux_1_2_armv7l.whl", hash = "sha256:8d5ceed027a42507a65f65746c9b1ada27dd898487306b2ae56b67af54fe5f28", size = 1502708, upload-time = "2026-08-06T14:06:53.707Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f4/d80bef4b92cdff36a58fc21eea99738af7087f8edc26f87c8e9102446d7e/ast_serialize-0.7.0-cp315-abi3.abi3t-musllinux_1_2_i686.whl", hash = "sha256:ee63de1439b46de948996d81170d7c0b467d8c7068be44968c176539d05f7c36", size = 1496545, upload-time = "2026-08-06T14:06:55.141Z" }, + { url = "https://files.pythonhosted.org/packages/e1/1e/1c7854a500b67d709f9185b3a5c14af6093e8c7b20d1b2d5c8a1edc1ea1a/ast_serialize-0.7.0-cp315-abi3.abi3t-musllinux_1_2_ppc64le.whl", hash = "sha256:90ecb3b1cebca24299eb84069ad5c0fb0e85d3f062167525dcc89a894641d619", size = 1558827, upload-time = "2026-08-06T14:06:56.884Z" }, + { url = "https://files.pythonhosted.org/packages/c8/34/e806b3768ec4249e36b000021cb31b441438e818141b654bfc1a7efc39e7/ast_serialize-0.7.0-cp315-abi3.abi3t-musllinux_1_2_riscv64.whl", hash = "sha256:47cb2d836aa8905f3b14d47cb298f630968544829b93c7eb8a08337f9860e049", size = 1417164, upload-time = "2026-08-06T14:06:58.272Z" }, + { url = "https://files.pythonhosted.org/packages/d4/84/9dc9d0fd28324ee89212ec074973bb4db5b2ff826afb0a045f2aee813a36/ast_serialize-0.7.0-cp315-abi3.abi3t-musllinux_1_2_x86_64.whl", hash = "sha256:7c54e159fbb62af577b4d20ac2ffb1f56ecfbe8c864a5222a4853adfdb245e25", size = 1446211, upload-time = "2026-08-06T14:06:59.695Z" }, + { url = "https://files.pythonhosted.org/packages/83/1a/02fcdac28c67ae7186a906b8b72ff8c94b7108b4d903a1e0a98260c3a295/ast_serialize-0.7.0-cp315-abi3.abi3t-pyemscripten_2026_0_wasm32.whl", hash = "sha256:1dc8030604a7b1abe0ba3f31572e61312d5bfbafa0ab8cc255f8c285002a9d88", size = 862416, upload-time = "2026-08-06T14:07:01.247Z" }, + { url = "https://files.pythonhosted.org/packages/ea/72/840b2c14b693f40a69ba43c650a88e0dadea875faa1430c8b97dc0613d1a/ast_serialize-0.7.0-cp315-abi3.abi3t-win32.whl", hash = "sha256:cef4d7fa14f6f259acf0c6cc4e9cd7a4ad773bdd13ba28c7d4127cb78e48d2c3", size = 1063825, upload-time = "2026-08-06T14:07:02.694Z" }, + { url = "https://files.pythonhosted.org/packages/ed/cd/6de6248744d30875b875dd8e43a76427b0c2bf42b735ee26149002b9ee04/ast_serialize-0.7.0-cp315-abi3.abi3t-win_amd64.whl", hash = "sha256:537f7a41a7bc1108e60cf8d6f5575beafe5b8a17d1a6ef0e758b4d4e4ad90d18", size = 1105533, upload-time = "2026-08-06T14:07:04.068Z" }, + { url = "https://files.pythonhosted.org/packages/00/30/d17d123c6d6558fad5b7aa026d7df45a639370156cec03d8cf33be9401e7/ast_serialize-0.7.0-cp315-abi3.abi3t-win_arm64.whl", hash = "sha256:913ddfdbbfaa6294dc841579211baa00d789a60d9ae1ad5e04a1e98de11926e4", size = 1076322, upload-time = "2026-08-06T14:07:05.605Z" }, + { url = "https://files.pythonhosted.org/packages/73/73/329d080bb3f1ef96d852fa017617827d6edb38cad31abd0c5f5b7cb5df16/ast_serialize-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:832e23968712b5b5e052e2095cfe050d32030f2af2d58c6f2c733e8148c82c47", size = 1184035, upload-time = "2026-08-06T14:07:07.273Z" }, + { url = "https://files.pythonhosted.org/packages/9c/48/2bb83025fa197d38f3380357b70adc9f14bc12d87df062dfcbcfeb9e76af/ast_serialize-0.7.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7196e1351389df3d1f8e2acffab03db167a14b5bd1f108d8530171b0866f6f56", size = 1177582, upload-time = "2026-08-06T14:07:09.138Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7e/f9b13d64699eddc59bae3d027971e7b913750231249319898a4552228190/ast_serialize-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a2343625ba33710f7e36a5be36e866ac7dbdd4369f11b5dfc6cd97d4aa85ecf", size = 1234638, upload-time = "2026-08-06T14:07:10.867Z" }, + { url = "https://files.pythonhosted.org/packages/58/e9/7fdbf053f3e35cb2a48d62f57c6a166e475ac9e7421c5004e0b602a7492b/ast_serialize-0.7.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4251412007121afee236b654b80aca3a8072a073abe2d984c582fb507bf1aa4c", size = 1235796, upload-time = "2026-08-06T14:07:12.548Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/a6b29764a60036fe35dec206b08c4c69a184aeb76d5b0ba00d5ab5acbf6e/ast_serialize-0.7.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76ca687ac87e97f8621d0be6f470aaa6307e4027ff1c449d36d1fb4f9fee1192", size = 1433051, upload-time = "2026-08-06T14:07:14.13Z" }, + { url = "https://files.pythonhosted.org/packages/73/c9/0eee1122c539407c2a7fbdd2461f33d3863fa20d38614f69f0cd7a6eca28/ast_serialize-0.7.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03e4fb60db9185c730db3521d73c6824dfd88d26ab2b2600a9ff1a466a79f0a6", size = 1255585, upload-time = "2026-08-06T14:07:15.682Z" }, + { url = "https://files.pythonhosted.org/packages/c3/d2/33bcfd2507f247b15efd827818ff462b376dd3c637e1576e6f0211a6c0d3/ast_serialize-0.7.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f058bd0b1e44276375730cfb11cd6beba00698dee2bb3d20b831ae319ca3d2b", size = 1258578, upload-time = "2026-08-06T14:07:17.135Z" }, + { url = "https://files.pythonhosted.org/packages/65/1f/61bfa3e75b50f5dd49cac0b8beb1e24d795d0648821bb531e97dff5c1a01/ast_serialize-0.7.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:54c8f5d009b2829bd98d7ebe0c29fcfc8f47f38e85d583d460837c54191b486c", size = 1253582, upload-time = "2026-08-06T14:07:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b9/2db828b7e1830411703e72626b692db540c26923c475f319d637657bb993/ast_serialize-0.7.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7f57b0a8ed664e163294e57b41c52c38527e5a0c73c01ead51f7073e1e652dd2", size = 1301023, upload-time = "2026-08-06T14:07:20.357Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f0/f93e40143f59ee37aebe9e5f8667f3c878232322febc03bb3b977afbf3d3/ast_serialize-0.7.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a0f4ce65748e2ef28046324254e9b1ad088fae56a93d69d07fbddf97d875b85", size = 1410178, upload-time = "2026-08-06T14:07:21.932Z" }, + { url = "https://files.pythonhosted.org/packages/1a/46/a316dddccecedafea3002a9ed1cd6666ab5e64c3094951625b5a1ef95a1c/ast_serialize-0.7.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:95219c374d0ac76639b26b66cca26e8cb090bf8c515d6bc376af484514d10151", size = 1509449, upload-time = "2026-08-06T14:07:23.53Z" }, + { url = "https://files.pythonhosted.org/packages/81/34/c58f49cc9da933af6ee0f802eb780c48648ae9d0ee9188cb802c10dce29f/ast_serialize-0.7.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:1e71d8879b8c3480eb461128bbf0d5ff87f5ce368fcdb10c850a95010aa5ece4", size = 1505368, upload-time = "2026-08-06T14:07:25.101Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ce/4c5a9ff4e2851ec38ecb8aeef8cb7e0a02308616279c04429342e12985f4/ast_serialize-0.7.0-cp39-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:85fa81ed590407c6ef6f85cac8e451051bf2623ecd875c4e124af8b8251de3ac", size = 1563486, upload-time = "2026-08-06T14:07:26.937Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/f239d17f902a2ce39da8e6dc034f48f45da93dfda658fa88189a02763510/ast_serialize-0.7.0-cp39-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:fd018e40c9462235a1d2d101b420cff6c577e5a51b2954ffc05b907a0807defc", size = 1427995, upload-time = "2026-08-06T14:07:28.773Z" }, + { url = "https://files.pythonhosted.org/packages/62/6c/024f58d8b52ce29717c54a578f0bbd844439fcb8eb442596e756fd6eaffe/ast_serialize-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:90a614b8c844620473b7445d31a2a6bf9500fdc4a8d1e2b6a70d40f38beea0e5", size = 1454215, upload-time = "2026-08-06T14:07:30.526Z" }, + { url = "https://files.pythonhosted.org/packages/12/48/f046778df64acef37a36a7338a9bdaa795f46b19d35a4d28bddcd8dfaec7/ast_serialize-0.7.0-cp39-abi3-pyemscripten_2026_0_wasm32.whl", hash = "sha256:e6cfb423d4a14d774b3b82f6509adbc5da065246b6ec679221ad133820e0f7f4", size = 868142, upload-time = "2026-08-06T14:07:32.139Z" }, + { url = "https://files.pythonhosted.org/packages/aa/fc/c862cc8d4d8d749f360035baa245fb3098b8b934c57122c0222ac5078762/ast_serialize-0.7.0-cp39-abi3-win32.whl", hash = "sha256:e818854e8521846f5a5271b1488c490231b8b6e02d0158ec42e57bc06dd764f0", size = 1068874, upload-time = "2026-08-06T14:07:33.895Z" }, + { url = "https://files.pythonhosted.org/packages/92/33/e846301850c18fa31598e342bb80b32f380c1bce285df571f5c3711960ff/ast_serialize-0.7.0-cp39-abi3-win_amd64.whl", hash = "sha256:942921b81440d3ea57f90370d5d29bf28dc81c0778e26b736013e83c7b258023", size = 1111845, upload-time = "2026-08-06T14:07:35.308Z" }, + { url = "https://files.pythonhosted.org/packages/6d/8c/4ee99be6306e72fac6051461794e5cd7895bbbdafe5b921a9a8c4b6fde1c/ast_serialize-0.7.0-cp39-abi3-win_arm64.whl", hash = "sha256:43b73cf3924aa49f241be6e5f6a19943c8e2e07a2786fc719cacaa54ac6fd2d5", size = 1083656, upload-time = "2026-08-06T14:07:36.828Z" }, +] + +[[package]] +name = "blake3" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/6a/4cc5a9dd40fd8a6d283fd3761e5f59c490109571ef8e3c73245417e5a305/blake3-1.0.9.tar.gz", hash = "sha256:5fa374fa5070ca084368776c19b420157eb0f2d3f091343d6bc59189929d62e2", size = 116872, upload-time = "2026-06-22T18:02:25.366Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/d2/9bdf8345c70993aaef635398f52edfb915d6e8ad2c000c801204e387c456/blake3-1.0.9-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a70c20542d5e7960983a0ff32999049a2b0e5ef1f22dbbbdfb51cf04828a4156", size = 344587, upload-time = "2026-06-22T18:00:34.244Z" }, + { url = "https://files.pythonhosted.org/packages/36/9d/be8b1f7f85b12bb45a0fade6ca7bdbf83a507d23d0b6141ba29fe69c8cea/blake3-1.0.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:72cdecf088a9d25e6ec79948a578995649b0dbee407e7a46c543a9ecc0f6f281", size = 328864, upload-time = "2026-06-22T18:00:35.59Z" }, + { url = "https://files.pythonhosted.org/packages/f2/78/66580635d744c826671fd219938caffb16281a26f62c4f856695d4233677/blake3-1.0.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42fa57bf462285ef16400601b0fd32214c248ba92505bbb94b1221ab9af5a092", size = 373795, upload-time = "2026-06-22T18:00:36.887Z" }, + { url = "https://files.pythonhosted.org/packages/b1/79/b5b17d3004bb81a5732c0b176c812703d200ed8c652b3b7713b9633bbe10/blake3-1.0.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b25ccde5a64be070f20e5c7a81da70292db40b164b6c77588cbd6230856badbb", size = 374183, upload-time = "2026-06-22T18:00:38.205Z" }, + { url = "https://files.pythonhosted.org/packages/3c/63/0d209c44b2041bbe130ced12a23c92dd995fbfe5bce7ee77fffea16f5cb0/blake3-1.0.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a800b87433955f37691b5f361ad29c7dd3ee089c9cd109adc5aea8e24bc4c1f", size = 446783, upload-time = "2026-06-22T18:00:39.493Z" }, + { url = "https://files.pythonhosted.org/packages/c5/51/efd1f9b8a9d3e9a0e235f3ced99a738529a1019fe78b3988e29d9c2fbba6/blake3-1.0.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6879739e7904b9c42afbedbcc2e8c36cebe140fb3fc3f5c492993579cf5cd516", size = 487369, upload-time = "2026-06-22T18:00:40.875Z" }, + { url = "https://files.pythonhosted.org/packages/8d/3f/a8dcaea9e0b26e419a540ca0cd6203c9fbb505e85b02b03c5a59bf9e6a45/blake3-1.0.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6edeb3d49a24c307995899b70dd47aa901d0e9ad51d2f8a79aba4f074f32d8c5", size = 383845, upload-time = "2026-06-22T18:00:42.251Z" }, + { url = "https://files.pythonhosted.org/packages/f6/10/e9907f5b86410d5071982aaf05d149ca4d4fd8acab7e77eebbc9a333c7b4/blake3-1.0.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcd56a7a972c4185070f7042ccc20166927eec3c0f98b8405f375d007b604a0b", size = 383851, upload-time = "2026-06-22T18:00:43.715Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/c7863a185550706a9624f6aa7b6d46470aaed0bb46a827c5cda2a7d03151/blake3-1.0.9-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:a288664d08dee154cc496e06e62517fc9e655ecec12b0d7db538d244ac79edf1", size = 380067, upload-time = "2026-06-22T18:00:45.249Z" }, + { url = "https://files.pythonhosted.org/packages/54/0a/e7af679c719368b400c9ba9c3460072aac2ba077ddbd4bc806fef28cda03/blake3-1.0.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:91db52a809b68b5bebe7c413ddcd230e1f759398e7fa7a873104595a4fa648b6", size = 549471, upload-time = "2026-06-22T18:00:46.793Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3c/37c1dd3539b7bd9b6d2eef019802aacdb4a3d48ab484b140603bbf9c5b5a/blake3-1.0.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cfaa671b07eb73883162ca940442193868358b0b904cfa266e4b74131ce966da", size = 591396, upload-time = "2026-06-22T18:00:48.122Z" }, + { url = "https://files.pythonhosted.org/packages/ae/55/4f0a23b72795292e74084834130900ea778c0583004519c86698dfffe1a5/blake3-1.0.9-cp312-cp312-win32.whl", hash = "sha256:ae47c3d5729ff89baa6ddf6de47fcfcc915985d39eb1bfcd6db653331f3c6fcc", size = 229271, upload-time = "2026-06-22T18:00:49.377Z" }, + { url = "https://files.pythonhosted.org/packages/12/91/7db93e4689f0f145bcb954dc62936e5f5090548a9fa20c6bbebfaeaa648a/blake3-1.0.9-cp312-cp312-win_amd64.whl", hash = "sha256:15566065ff90ab3da46ec0be1417406f00507af902b6fb0fbc6563e77f02fc42", size = 218220, upload-time = "2026-06-22T18:00:50.659Z" }, +] + +[[package]] +name = "boto3" +version = "1.43.66" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/8f/92486dc60e9caf63a766bce02c561381455169a1b7090548d1fdc14d6b8d/boto3-1.43.66.tar.gz", hash = "sha256:ffc77129a4e5519bdbd9b278e4fe9e6276c9d951e0d2b60d626977bdb957cb38", size = 112668, upload-time = "2026-08-06T19:38:42.066Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/bc/131d596cf673f7b7c6b52ff88fa05f73bbdf9dff70d93e31d4b62645def3/boto3-1.43.66-py3-none-any.whl", hash = "sha256:8d097a41e2f545c25252105570f782bb035b1ac13d6213c772d1c895dc7cedeb", size = 140027, upload-time = "2026-08-06T19:38:40.651Z" }, +] + +[[package]] +name = "botocore" +version = "1.43.66" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/81/9ce1f5fe88b4b1429edf83189b8994ffb9883fc20bdd46b7ee9d1cc1da24/botocore-1.43.66.tar.gz", hash = "sha256:dde324cbe8be14b536b78f4fafe192f94fffcc70716bde804044e62495af8c3c", size = 15880416, upload-time = "2026-08-06T19:38:37.603Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/e6/53f0e28dea0f17a1b041bb3356d0c21fda7ba4198a515cfaf4d5f3088fe3/botocore-1.43.66-py3-none-any.whl", hash = "sha256:0fa62529579469a9224c186eba87e7e561db87dfad20c63ce5d52e427c7fa325", size = 15566310, upload-time = "2026-08-06T19:38:34.446Z" }, +] + +[[package]] +name = "c2pa-python" +version = "0.37.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "pytest" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "toml" }, + { name = "wheel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/ec/416d05dc0cffc362f24cb33121aeddb621cfe5f06b239b0051aa25b28079/c2pa_python-0.37.5.tar.gz", hash = "sha256:185cd00c18d8386a0c6c8c5af19434005406626545e6250e1273f4cc14389739", size = 112944, upload-time = "2026-08-05T23:09:56.409Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/f2/344074f26373f3c596a98549b0a7755b1cf6036ed4a831ad74526ac33d80/c2pa_python-0.37.5-py3-none-macosx_10_9_universal2.whl", hash = "sha256:8f719bd53a08bb54a4e8b761825db426d153430199821a4fcac1c13efe26d309", size = 16150883, upload-time = "2026-08-05T23:09:21.934Z" }, + { url = "https://files.pythonhosted.org/packages/f3/38/bd924e7f829b156fcf967923d26918fd4cc3435860055ae8b1b46d97d982/c2pa_python-0.37.5-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:72a9b074f3fecf67fb1740003869fe17c2d664ab79e6fc0669d3a77dc01e6699", size = 14116139, upload-time = "2026-08-05T23:09:25.589Z" }, + { url = "https://files.pythonhosted.org/packages/74/50/1128ae57644c079c75dcfeeaf5b51e199246b17f745d42e9a929d224b199/c2pa_python-0.37.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:95e446663cd53d9292fd04afb84996c3be9a4aeea1ac076440d9a6c6477da921", size = 13785203, upload-time = "2026-08-05T23:09:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f0/f5291ba6f3bc778575af06d9a6630d841432b7cf8136ae57e8889b212d8d/c2pa_python-0.37.5-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:8fc4ce81ae5449a65981ce10e33c91c33a85a10b3aed1124d580ad5ce15b1ea7", size = 14006289, upload-time = "2026-08-05T23:09:32.566Z" }, + { url = "https://files.pythonhosted.org/packages/57/33/e258809ad6ae1ee7c9af29117bd8addf87db9e0a0b53354ac668b2f2e4a4/c2pa_python-0.37.5-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:82bf2dcc5f184a40d7b65a5804b3e6251d52e6e65958cfbc0dc80321eac4bb33", size = 14652564, upload-time = "2026-08-05T23:09:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/95/2f/5c2ebd8baa36c4422f4827323a6a67c07ed57898f3500f689ab0d7b31435/c2pa_python-0.37.5-py3-none-win_amd64.whl", hash = "sha256:c122680aa05ea12bbe061c69333c0137f4f2f8c7906ae06fec255db346d788b8", size = 86368147, upload-time = "2026-08-05T23:09:45.232Z" }, + { url = "https://files.pythonhosted.org/packages/39/6f/f54775038b6a469951fe9899249ff3f8545421f64cc5e6a718af092f383d/c2pa_python-0.37.5-py3-none-win_arm64.whl", hash = "sha256:1ed2f1bd1d69e1ac243a9d769e5fa1047d5f9be3fed3206bb3c0a68c3c9e0bce", size = 83916232, upload-time = "2026-08-05T23:09:53.31Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "cffi" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz", hash = "sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be", size = 530807, upload-time = "2026-08-03T21:21:18.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/69/43965eccfdead3b9220015fd1320e117be8c6ed01a62ffab76eeb752f5d5/cffi-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0", size = 184821, upload-time = "2026-08-03T21:19:44.887Z" }, + { url = "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf", size = 184719, upload-time = "2026-08-03T21:19:46.129Z" }, + { url = "https://files.pythonhosted.org/packages/56/e6/8941622732edec876dd17d0453dce07317ae96db34f2ec1436c9d3785986/cffi-2.1.1-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a", size = 214799, upload-time = "2026-08-03T21:19:47.218Z" }, + { url = "https://files.pythonhosted.org/packages/44/de/f98430906df1545ffde0d543dd124a7a439bc2cd32b36b9c53f805df7333/cffi-2.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890", size = 222389, upload-time = "2026-08-03T21:19:48.331Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/717f1526b9957b34456313c31645c5b82b8fb5c3fe9e4752999be7128bfc/cffi-2.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50", size = 210249, upload-time = "2026-08-03T21:19:49.543Z" }, + { url = "https://files.pythonhosted.org/packages/64/b3/f8aa4f3e34986c7e4ec45072d1b1b9dd295b6b18007b45518d79726dd725/cffi-2.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e", size = 208775, upload-time = "2026-08-03T21:19:50.918Z" }, + { url = "https://files.pythonhosted.org/packages/b1/db/dceb9dd5b231e1da801793f8acc9f3c52a7e1afe40bb1aae37e02b0faad5/cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf", size = 221822, upload-time = "2026-08-03T21:19:52.054Z" }, + { url = "https://files.pythonhosted.org/packages/a0/d2/6cd24ae3be000a634109c247d1475d62e5616d0dc78c82770942ec384248/cffi-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517", size = 225232, upload-time = "2026-08-03T21:19:53.109Z" }, + { url = "https://files.pythonhosted.org/packages/cb/52/3fa190537004dd7f0ab860a6dc7c0175b8667f68d1e618a46f5498d30250/cffi-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735", size = 223597, upload-time = "2026-08-03T21:19:54.515Z" }, + { url = "https://files.pythonhosted.org/packages/80/fb/0bb75b7039588c074b37ae99f40d9bfddf990ecb2fbc346ebccd2e56b9be/cffi-2.1.1-cp312-cp312-win32.whl", hash = "sha256:046bfc24911b37851ee1b51aab8bffe713d89c68c6a057b09484ce9fd5f69b4e", size = 175292, upload-time = "2026-08-03T21:19:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/d9/79/615cc094e2fb508cade7de88d3b4f6c4ec2bab695c97bce9153dc65aadf5/cffi-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f53e442b08449d42821fa4a4fba000095af9f62742a500f978a9f557ec44339a", size = 185919, upload-time = "2026-08-03T21:19:56.89Z" }, + { url = "https://files.pythonhosted.org/packages/70/c6/d0ea84713fe46b243a436a18fcd47d639732747e21635c8a27191b06dc30/cffi-2.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:7bde5e4cc5c10140859842b9d383af292b22639a4dffb725314baf45968cef80", size = 180093, upload-time = "2026-08-03T21:19:58.155Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0", size = 319300, upload-time = "2026-07-07T14:33:15.666Z" }, + { url = "https://files.pythonhosted.org/packages/ec/96/5d9364e3342d69f3a045e1777bc47c85c383e6e9466d561b33fdb419d1f9/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9", size = 215802, upload-time = "2026-07-07T14:33:17.031Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4c/5361f9aa7f2cb58d94f2ab831b3d493f69efb1d239654b4744e3c09527cb/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44", size = 237171, upload-time = "2026-07-07T14:33:18.576Z" }, + { url = "https://files.pythonhosted.org/packages/50/78/ce342ca4ff30b2eb49fe6d9578df85974f90c67d294113e94efdd9664cbd/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9", size = 233075, upload-time = "2026-07-07T14:33:20.084Z" }, + { url = "https://files.pythonhosted.org/packages/01/c4/4fa4c8b3097a11f3c5f09a35b72ed6855fb1d332469504962ab7bafcc702/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd", size = 224256, upload-time = "2026-07-07T14:33:21.747Z" }, + { url = "https://files.pythonhosted.org/packages/87/3a/ad914516df7e358a81aae018caa5e0470ba827fa6d763b1d2e87d920a5f6/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84", size = 208784, upload-time = "2026-07-07T14:33:23.313Z" }, + { url = "https://files.pythonhosted.org/packages/d7/74/3c12f9755717dfe5c5c87da63f35d765fa0c00382ec26bf23f7fae34f2ba/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b", size = 219928, upload-time = "2026-07-07T14:33:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/33/9a/895095b83e7907abd6d3d99aad3a38ad0d9686cc186cb0c94c24320fe63e/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde", size = 218489, upload-time = "2026-07-07T14:33:26.42Z" }, + { url = "https://files.pythonhosted.org/packages/a1/34/ef5c05f412f42520d7709b7d3784d19640839eb7366ded1755511585429f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39", size = 210267, upload-time = "2026-07-07T14:33:27.952Z" }, + { url = "https://files.pythonhosted.org/packages/83/dc/9b29fa4412b318bf3bfea985c35d67eb55e04b59a7c3f2237168b0e0be6f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62", size = 226030, upload-time = "2026-07-07T14:33:29.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/42/6dbc00b8cd16011691203e33570fa42ed5746599a2e878112d16eab403a3/charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642", size = 151185, upload-time = "2026-07-07T14:33:30.781Z" }, + { url = "https://files.pythonhosted.org/packages/80/cc/f920afd1a23c58ccd53c1d36085a71893a4737ff5e66e0371efab6809850/charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0", size = 162557, upload-time = "2026-07-07T14:33:32.176Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/0386d43a261ff4e4b30c5857af7df877254b46bec7b9d1b74b6bf969a90b/charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2", size = 152665, upload-time = "2026-07-07T14:33:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" }, +] + +[[package]] +name = "click" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cryptography" +version = "50.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/41/6cbdcf9142d00fe82836fbb51e503e58088575cf7a0fe1dbff6695bf0840/cryptography-50.0.0.tar.gz", hash = "sha256:eeac2acb5a20ed25e0ad6d1df9891a520b78b404266b6d11778f25d5d691a6c9", size = 880201, upload-time = "2026-07-31T14:25:10.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:031e2d5dd4bb9caa3ca9c82e5a197fd8ae680232cee62603d1a813f3f07e3d03", size = 4001252, upload-time = "2026-07-31T14:23:33.331Z" }, + { url = "https://files.pythonhosted.org/packages/57/ef/8f2df13c7216bcad3e1c74e07f6e193d93e998e114f524a53877c9af27ad/cryptography-50.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd9192b7b70c573d7f214eb1ae35e00d359f6f5e4b27c7e21e30de1fc6204645", size = 4719554, upload-time = "2026-07-31T14:23:35.611Z" }, + { url = "https://files.pythonhosted.org/packages/d9/41/029086c34d91052fc3b88bcc8056f709a7c915c7a23b235a54eb800b1c97/cryptography-50.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:06a32a980526a6ab9a4b9bf8f7385800791e2bb960903cb6b530e4817509a3b7", size = 4702130, upload-time = "2026-07-31T14:23:37.635Z" }, + { url = "https://files.pythonhosted.org/packages/7d/ff/b6ce0954962e7f7b969f850a883744197bb3910bdfd7b6da162eab7d9f68/cryptography-50.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a1b30560f2acc95aa8b2e06e716a13dbfc97314747b80d9707e307f77b40d6b3", size = 4725244, upload-time = "2026-07-31T14:23:39.471Z" }, + { url = "https://files.pythonhosted.org/packages/06/1e/63a1027cb7fec360a182208e1b7767d5aa1fe57be3d6aa856e69a321edc0/cryptography-50.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:8d89f3976b10b4ce31118de72329025f70d2c6ead14a8217c5514dd2c6d5a78f", size = 5342265, upload-time = "2026-07-31T14:23:41.286Z" }, + { url = "https://files.pythonhosted.org/packages/6b/72/a1116d683a6d7ece94590013882515de087edf9ef0e6292aae615a44df73/cryptography-50.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b42a28c1844fd9de8f3f7d540e36b66f3a9c83fceac7170ebc7a6a19edd9dcae", size = 4734609, upload-time = "2026-07-31T14:23:43.139Z" }, + { url = "https://files.pythonhosted.org/packages/15/37/36a9c479bbe49acea2636c7fd3360d20f7b7e079c300352011c44850b181/cryptography-50.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:900131fafd8aead39ac7dd3a7e833be754c17a95cfd91221636949fe4eb0aa8a", size = 4356517, upload-time = "2026-07-31T14:23:44.939Z" }, + { url = "https://files.pythonhosted.org/packages/32/98/8a151d64367204cbc63ec65d37502f1d9c53cf4bfc6ec3c532614dbec60d/cryptography-50.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:07949c449a1abcf60d1ee6e88956d89404c7df3c8258f46589e912988e551987", size = 4724529, upload-time = "2026-07-31T14:23:46.93Z" }, + { url = "https://files.pythonhosted.org/packages/22/f6/ec13b470172126464a86bf54d2294a46d29837fc51ba3e45d4047946fb5e/cryptography-50.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:f89831ef99dd7dd169ab06d63a831adb9e20a87aac6d380266bbda5823349169", size = 5299852, upload-time = "2026-07-31T14:23:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/da/3a/f05e32c99d440c9bb891ea0e36c9091891e36be5a9a87ab2ee6ea20729f6/cryptography-50.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:82148ec5bddac30b51a5b3c1945075f896fa022cb93f8e4a01e9f6ee95292c5f", size = 4734462, upload-time = "2026-07-31T14:23:50.861Z" }, + { url = "https://files.pythonhosted.org/packages/ca/dc/bd72b26be8953f80625f63151efd38eee71c76ca6cf591c08ff34615a79e/cryptography-50.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1489e263a8048bb8b6a8bac662eb2d402ea5d2b7b4699b72f385f1e2772db105", size = 4852708, upload-time = "2026-07-31T14:23:52.715Z" }, + { url = "https://files.pythonhosted.org/packages/27/20/c930314a2ab476d15dec966ec87e2e9637bb02b06106b12c0396c57bb603/cryptography-50.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7cec5b856506da6defb290f30c9ee687d5f5e8cb0bd3f6459dde43b0b4fa40ef", size = 5004179, upload-time = "2026-07-31T14:23:54.887Z" }, + { url = "https://files.pythonhosted.org/packages/32/2e/c9db68a0c4bfa28e310707527c0ee3a2bd254104d2e02e68f368e197aa4c/cryptography-50.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:bd1c592e4d5974f0d08d4888e432157adba757c66da0246918e43677fafa2d30", size = 3840395, upload-time = "2026-07-31T14:23:56.677Z" }, + { url = "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ccdc4a71a4dabae05de219404f9f4abc38e3b58422177ff93d0da05967dafa07", size = 4036009, upload-time = "2026-07-31T14:24:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c6/7a6202a534e32103a285b7834a120869557fe198d51d7cfe59754c8bda9c/cryptography-50.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:910e1d2668e7de9648f2bcee30e180db2a6b15c30f887d7c4c93ddf96e3992e3", size = 4745252, upload-time = "2026-07-31T14:24:26.118Z" }, + { url = "https://files.pythonhosted.org/packages/85/4f/0fa8c2f4428198f15d9ff8d63400e27afbf94ce833f6108da1eb3753f945/cryptography-50.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a91296cb61e8df6f86d0c19cc4068228da256bf59bf86049fbd821084565327f", size = 4728939, upload-time = "2026-07-31T14:24:27.994Z" }, + { url = "https://files.pythonhosted.org/packages/d1/63/54dd723490ba2dc09b299682c10b38db38f159728bcaae8c591b8af2f22d/cryptography-50.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e722f16708d854fe924790e051061f6704a472c3bac347b6fd88033ea8dd0dc5", size = 4748483, upload-time = "2026-07-31T14:24:30.254Z" }, + { url = "https://files.pythonhosted.org/packages/1d/dd/7c77d26285cc7f6991efce64a0f5b4f9383bfa5dd8c5033003eaf7db4cdb/cryptography-50.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d764dcf130c428ef66786f866dd750f53182bc608813489915e9fc106bb0c82f", size = 5367599, upload-time = "2026-07-31T14:24:32.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/c9/f60aed34c013f317f92817b6c171c2d22a78270fa41109bd4b08af26b194/cryptography-50.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:105110f43a471dbd0060b9c9516cb8a6a79233631a04cc2ba16f28323ac6e025", size = 4762647, upload-time = "2026-07-31T14:24:34.599Z" }, + { url = "https://files.pythonhosted.org/packages/be/f3/f9a0173b139372c3a48ed98154b45cc6b9de17c789d5ab552e621c293609/cryptography-50.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:828743d939e9629bc267b8e2d08d8bb67cd4319c771a33d4b18b22dd8fb7440a", size = 4385197, upload-time = "2026-07-31T14:24:36.647Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/83bb81f6e569bc38e1e4a7bc80f29b46bb9601920bc455fc8e888f5d5742/cryptography-50.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a8183b489dc1f7f80f135780fadc1108f14b31b8a40411c7a5b17425f65f28b", size = 4748095, upload-time = "2026-07-31T14:24:39.493Z" }, + { url = "https://files.pythonhosted.org/packages/6b/16/d3008eff98c764979865834c3d386d4fd041b5f52e7f34fc29ac1a5eb515/cryptography-50.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6e7d61120573a7f2cd94cc095f9e81f6967c61ccdf194285aa143ecec8e0b708", size = 5325948, upload-time = "2026-07-31T14:24:41.556Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f8/d97f9603efda3888187bfdb893f26c41be4735c10631d05d284ee6b047c4/cryptography-50.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:37fdb0d0111f1e2ff07139dfb79f1b49531f8e213c46f1163dd7642979b58c47", size = 4762400, upload-time = "2026-07-31T14:24:43.636Z" }, + { url = "https://files.pythonhosted.org/packages/64/a2/4615c8f7d81a00b1d6e6afe19f694e1543582349fb5f4076f6cb5dc36485/cryptography-50.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87f62a3d3b9888ed0fdde100ec06aa61ca9cd44bad9057d1dff9a516b5f5bb9", size = 4878208, upload-time = "2026-07-31T14:24:45.522Z" }, + { url = "https://files.pythonhosted.org/packages/d2/1a/efcfb02f91407149a0dacffffab791f7e19bf6385f63b3666dc8b5e5c9c8/cryptography-50.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:65c2c3add92b45fd0709db8594536aea39c2a67af0e27ffcf049c498501140b7", size = 5037050, upload-time = "2026-07-31T14:24:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/57/30/4a22984d4f1bdfb8c054f07a92bc176b97a3134cc1d6c4b3bffb1f3688b4/cryptography-50.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:d24fead1d4d076e1bfb006dcec392074a3cd8d7b4fc8a595aa64073b2b7a96ba", size = 3874135, upload-time = "2026-07-31T14:24:50.085Z" }, +] + +[[package]] +name = "cuda-bindings" +version = "13.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-pathfinder" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/67/5e7dba1ba576dd73da5dee894ca076ca5e959450dfff66d6d510a255d1f7/cuda_bindings-13.3.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7855c4868aabc0cfae28abbe83d56734bdfbd08f08fc234ac1912a12858bf49", size = 6025351, upload-time = "2026-05-29T23:11:49.685Z" }, + { url = "https://files.pythonhosted.org/packages/39/2a/6d2e9047d1fb243dbaa364b01e0297534b9ed7fd27dba1c9f361519cf69b/cuda_bindings-13.3.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e32d08f71ebcdf00f0f41eab2eb37e8da94c8ed411cc9f7f7a019ce6b34abe3a", size = 6657965, upload-time = "2026-05-29T23:11:52.227Z" }, +] + +[[package]] +name = "cuda-pathfinder" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/b4/d088047afe39827556df21118cac9ffd20cc3f968c99a7681494d1eb333c/cuda_pathfinder-1.6.0-py3-none-any.whl", hash = "sha256:1503af579d8379c24bdd65528379bc57039b0455be9f5f9686cf8e473a1fce51", size = 54591, upload-time = "2026-07-21T15:03:56.224Z" }, +] + +[[package]] +name = "cuda-toolkit" +version = "13.0.3.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/c7/a79086a62c98befcdb8349656c6f114e2db3b8b2422f6e25c97a7f2a9a3c/cuda_toolkit-13.0.3.0-py2.py3-none-any.whl", hash = "sha256:d693caaa261214ddd7dbb60d68e71cbed884e68c2be7509778f3051da0b91c3f", size = 2512, upload-time = "2026-04-14T00:50:08.173Z" }, +] + +[package.optional-dependencies] +cublas = [ + { name = "nvidia-cublas", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, + { name = "nvidia-cuda-nvrtc", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +cudart = [ + { name = "nvidia-cuda-runtime", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +cufft = [ + { name = "nvidia-cufft", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, + { name = "nvidia-nvjitlink", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +cufile = [ + { name = "nvidia-cufile", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +cupti = [ + { name = "nvidia-cuda-cupti", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +curand = [ + { name = "nvidia-curand", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +cusolver = [ + { name = "nvidia-cublas", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, + { name = "nvidia-cusolver", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, + { name = "nvidia-cusparse", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, + { name = "nvidia-nvjitlink", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +cusparse = [ + { name = "nvidia-cusparse", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, + { name = "nvidia-nvjitlink", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +nvjitlink = [ + { name = "nvidia-nvjitlink", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +nvrtc = [ + { name = "nvidia-cuda-nvrtc", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] +nvtx = [ + { name = "nvidia-nvtx", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')" }, +] + +[[package]] +name = "filelock" +version = "3.32.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/57/3ba6e6cb097f85b855b00163d169f35365f44277df044dcf96d55b8f62a3/filelock-3.32.2.tar.gz", hash = "sha256:c33351e1f49cae33414acbc6d56784e6ecee82514ec90795da1161fc4836b5b8", size = 217172, upload-time = "2026-07-29T22:46:04.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/e8/72f8cef9fdfeffe06213fe8508039396ee48daa0e3259457ed766173bfd6/filelock-3.32.2-py3-none-any.whl", hash = "sha256:87dd94cf281e586d135fa51132b8e3d9a598b316e90377a288663c9321036c82", size = 98830, upload-time = "2026-07-29T22:46:03.52Z" }, +] + +[[package]] +name = "fsspec" +version = "2026.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/78/f34251dadb8f3921264a1d9b8946f5e542014ee2614b285261b4e40e6775/fsspec-2026.7.0.tar.gz", hash = "sha256:c803c40f4cf860b49dea58ee3e1c33cb9c790520e233537e1340049f89b82a88", size = 317040, upload-time = "2026-07-28T16:34:51.052Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl", hash = "sha256:b57ddbafedfaef7018c1ecab32aa200a9d7ca26b77965f64e48b70061249d279", size = 206583, upload-time = "2026-07-28T16:34:49.538Z" }, +] + +[[package]] +name = "gen-worker" +version = "0.93.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "blake3" }, + { name = "boto3" }, + { name = "c2pa-python" }, + { name = "gguf" }, + { name = "grpcio" }, + { name = "huggingface-hub" }, + { name = "msgspec" }, + { name = "protobuf" }, + { name = "psutil" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tomli-w" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/6b/826f52ced372c48a3ef97a30282072a5ecd52f3157d35fb0629eeb442453/gen_worker-0.93.3.tar.gz", hash = "sha256:c92ca03a2b0fe59a76265abd8de6950fdafc5524735d0d4f1f9447923358cb1f", size = 1607538, upload-time = "2026-08-07T03:22:44.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/a8/3bb23365239dc230ea4d14f6137e15ede7f6faae578203e82adc35db7b31/gen_worker-0.93.3-py3-none-any.whl", hash = "sha256:53d44aa27932ba5f71b4fd17e5d948c36f1f54d44e0e461a4b384353d87e089e", size = 1764478, upload-time = "2026-08-07T03:22:42.718Z" }, +] + +[[package]] +name = "gguf" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/ae/17f1308ae45cd7b08ebb521747d5b23f4efc4d172038a4e228dd5106c3ff/gguf-0.19.0.tar.gz", hash = "sha256:dbadcd6cc7ccd44256f2229fe7c2dff5e8aa5cf0612ab987fd2b1a57e428923f", size = 111220, upload-time = "2026-05-06T13:04:03.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/bb/d71d6da82763528c2c2ed6b59a9d6142c6595545a4c448e2085d155e88c2/gguf-0.19.0-py3-none-any.whl", hash = "sha256:70bcd10edfe697fb2dad6e40af2234b9d8ece9a41a99761405121ebda1c3c1cd", size = 118475, upload-time = "2026-05-06T13:04:02.588Z" }, +] + +[[package]] +name = "grpcio" +version = "1.83.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0c/98/304898ac4e04e2d5e4e4c2eadc178b1f2a16d5f4bc2f91306c87d64680b9/grpcio-1.83.0.tar.gz", hash = "sha256:7674587248fbbb2ac6e4eecf83a8a0f3d91a928f941de571acfd3a2f007fbc24", size = 13428824, upload-time = "2026-07-23T15:20:37.759Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/2b/51e32514a4e9b715375c99721aadff0f24164cc2049b8269eda4de82a814/grpcio-1.83.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:28f6c35ac8fcf10e4594f138e468f194360089dde40d126a7033e863fc479930", size = 6303167, upload-time = "2026-07-23T15:19:33.78Z" }, + { url = "https://files.pythonhosted.org/packages/39/33/b5b50fc2c6fbe350e04814047bb2d409feec7b36ef8b170254c050e06bc0/grpcio-1.83.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:33898e6a28e4ae598f1577cb1c4fec2a15c033d0ec52b9b45a09610dd045b9da", size = 12160538, upload-time = "2026-07-23T15:19:35.958Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5f/734e72e7b9f79bcf0b2c270b8d3bca0e4ebb97a27a50d06240b145f6d41e/grpcio-1.83.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6fb8a1dd0c6f0f931e69e9d0dc6d1c406ed2a44fa963414eafba07b7fb685d16", size = 6869310, upload-time = "2026-07-23T15:19:38.607Z" }, + { url = "https://files.pythonhosted.org/packages/a4/17/a1735f215b2a5cd43c38b79eac072ad197e61be9829905b6b29550abd0db/grpcio-1.83.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2b5e75c34842cd9c1b95285ca395c6a569664b81e3ffa6b714125922942abaaf", size = 7613472, upload-time = "2026-07-23T15:19:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/b2/78/c9e81f806ac704b6b145cb01628db398985b1f8dfdc10e23b55fb0902b3d/grpcio-1.83.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeb339838db07600481ef869507279b75326c75eac6d10f7afa62a0da1d2bcdd", size = 7040616, upload-time = "2026-07-23T15:19:42.349Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ba/94cd5af859876049d340480acbb61a959096c84b567f215534faa78d0424/grpcio-1.83.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f47d62808b4c0a97b78bff88a6d4ca283a2a492b9a04a87d814af95ca3b9c19c", size = 7570491, upload-time = "2026-07-23T15:19:44.357Z" }, + { url = "https://files.pythonhosted.org/packages/3e/15/108d30d5a5c964312ae8b9cb0e8cc5b3c1cc68d8f757cca52b3565534d26/grpcio-1.83.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:62003babc444a606dcd1f009cd16391ce23669ae4ad6ec267a873da7937a69f5", size = 8605036, upload-time = "2026-07-23T15:19:46.454Z" }, + { url = "https://files.pythonhosted.org/packages/ea/23/3828ae13c3db8233d123ad612747665817b952d8a954f32390230b582336/grpcio-1.83.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1aa567f8c3f19850ffd5d2858c9a8ea7c80f0db6c01186b71eb31e923ec984f5", size = 7981587, upload-time = "2026-07-23T15:19:48.913Z" }, + { url = "https://files.pythonhosted.org/packages/17/5b/77af31228f55f55a2a5112bb0077ad0a1c4d23dbb0c2853a62475bbdcc14/grpcio-1.83.0-cp312-cp312-win32.whl", hash = "sha256:cb2906c61db4f9c64cc360054b5df70eeb81846228e9e56a4944bd415a63dadc", size = 4394004, upload-time = "2026-07-23T15:19:50.618Z" }, + { url = "https://files.pythonhosted.org/packages/c0/da/f706e39550e7a3732ce2b9c5926107a93d74a802775b19b642a6df27dc96/grpcio-1.83.0-cp312-cp312-win_amd64.whl", hash = "sha256:1c699bbb20f143c8f2bff219de578aa2dc1f919399d67dc702b038b986ee62df", size = 5158525, upload-time = "2026-07-23T15:19:52.246Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/ab/522a2ab67f27971a9d48ca666d4fca85ef7d5282d142e31fd087e27b1bbe/hf_xet-1.6.0.tar.gz", hash = "sha256:2e58454a340b3556dfa4972d5451aff4fba8dd42a236600ba1a1d2b1514f0fef", size = 920527, upload-time = "2026-08-03T22:33:13.243Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/50/7afa2c9c787405864fc47a0d1bbc02c62e9101947ed43c1f43899fc7d91d/hf_xet-1.6.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:633dc0cd71d32da58ab8c03ad38e2fac452c15c2b0a2866ebf6ededfe0a5061d", size = 4071729, upload-time = "2026-08-03T22:33:00.721Z" }, + { url = "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:f0906082d9932ae0c0057fa194041c22b4e2cdb46b2592ef3b91f020d62a081a", size = 3876287, upload-time = "2026-08-03T22:33:02.251Z" }, + { url = "https://files.pythonhosted.org/packages/67/4e/a28359bf1c1ecf11eba22123168c138698f7cb576ac678f5a2e16cd5da08/hf_xet-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d62671bb130879cef0ee4c9ebe47a14af6c66ec53e6d84dc15936e5ffdfac82f", size = 4464663, upload-time = "2026-08-03T22:33:03.802Z" }, + { url = "https://files.pythonhosted.org/packages/9a/69/1f0cbc2fb22ae6082d094f743d1b8945a3f36f6089cb95f42b7ee348cda7/hf_xet-1.6.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0e6e21fa3cdfcdcd76748564bf593870a5e013f47d97cf10aed63aa222cff5b7", size = 4262538, upload-time = "2026-08-03T22:33:05.287Z" }, + { url = "https://files.pythonhosted.org/packages/d1/3a/4f4f2301ade26e404462d3336fa11f7958d914cabbabdd6e03c3c5d5658c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4fc74352a17015bd0ee90038bc9efe38db894cde45f268b6712b04fce8cd0acb", size = 4460520, upload-time = "2026-08-03T22:33:06.81Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5f/311725e2a905534dfee2dcb5b08414f249147f1f12252bfc2bd24caa075c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4f71cba6129110c3374a33f919001ff130488fc23553698e34cc1c2a1198c", size = 4675937, upload-time = "2026-08-03T22:33:08.616Z" }, + { url = "https://files.pythonhosted.org/packages/98/b7/8c59a66d15205024662f1d66968136f13893f96df1ddc5087e2e281fc95f/hf_xet-1.6.0-cp38-abi3-win_amd64.whl", hash = "sha256:fb4fadde1b2b70bf4c0c14a6dccbe7194b1c28947fefd5bbe3fed9d940676c3b", size = 4033128, upload-time = "2026-08-03T22:33:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/73/63/ca511b6f802f28cf3489b280fe77475bcca8de85e81a6299d7916b5b5555/hf_xet-1.6.0-cp38-abi3-win_arm64.whl", hash = "sha256:3dc3e35441ba395006af5aaacc40ef2e603c51ef46c3530b9156185f00935ea3", size = 3859359, upload-time = "2026-08-03T22:33:11.725Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "1.26.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "httpx" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/89/64/bfe23dab749cb2342e1e13b61c9e684ce46b4d189c7d433cd26f76f52baf/huggingface_hub-1.26.1.tar.gz", hash = "sha256:7c28860777594ac679233f571552d0e46df34ed4e4239e844190fad3ca05e4cd", size = 936700, upload-time = "2026-08-06T09:42:24.859Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/a7/b519cd01e57b685c5f3e9db02cb1bd7aaade35fb6554e0d36bee6d6aae28/huggingface_hub-1.26.1-py3-none-any.whl", hash = "sha256:d8676e4ec96c1e481a22a93232bd86d73bbac643fb767399aefaeaa503890fb0", size = 780754, upload-time = "2026-08-06T09:42:22.497Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jmespath" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, +] + +[[package]] +name = "librt" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/ee/999b97f4b8eb28c4416f9f8a6708077daa1639145cde1c25ac76517df966/librt-0.14.0.tar.gz", hash = "sha256:474eedc5e910d88c1a12193a238f69b2522561d6f10bda9fbe9e70961d2e64e3", size = 214292, upload-time = "2026-08-06T14:52:21.049Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/7d/ca9feff7e486d74ae3efb5bc66ab95d15fe29090bd902c24be660deed7a3/librt-0.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:171dd324dd6b269503e3777b9cc66c1c6f7bbcbf9b9403b96c5901377bde8f4e", size = 150997, upload-time = "2026-08-06T14:49:56.049Z" }, + { url = "https://files.pythonhosted.org/packages/9b/97/9452106e9b2b0f5c771c5656af763927c351b60363e6496fff2775280507/librt-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c648d09e7842f42cb8bcae41b6a39d6536448612ee4c516ce58b284300f5a066", size = 155241, upload-time = "2026-08-06T14:49:57.344Z" }, + { url = "https://files.pythonhosted.org/packages/8a/5b/eeb378de1b84761d555e100e5c69facfa6cb6266ef4a11baab55d64ac6b7/librt-0.14.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9bb36c48a582caf7d604bc3f3554b550431d1aa6b131a618e33e2816261620a", size = 503094, upload-time = "2026-08-06T14:49:58.775Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b4/e5c372c7c543cbe721b25ac6837190f27d627838a9208b7069e167c06f9c/librt-0.14.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:93c52e7d5f9ac110db854a4c49cc5fb0362e77047e7ebf71f1a6f35829395d47", size = 496536, upload-time = "2026-08-06T14:50:00.43Z" }, + { url = "https://files.pythonhosted.org/packages/e0/81/9d64cc59740a37a68e4bcad1fb1734a354c6e2899cc66871feff4c1a9032/librt-0.14.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31e9931b28896420c0870332eefc8e966121adf8013850d14a22d694c17c8cdf", size = 531811, upload-time = "2026-08-06T14:50:02.018Z" }, + { url = "https://files.pythonhosted.org/packages/87/93/c643336b08dfd38e27a77ad3811ec7f18c2aa83677332f21300430ad5fcb/librt-0.14.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:52e3630f4d00aa1fd1c224e2ae7ea2a31058493247f765393b7aac2bd0f3bf01", size = 524425, upload-time = "2026-08-06T14:50:03.528Z" }, + { url = "https://files.pythonhosted.org/packages/3f/19/aa78ba06cf8546a0f3d5ef6985b721d4bad60f1d938e147b6576f826dae7/librt-0.14.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c66f6183f4dde136d5567fbd192c86236c8a89caa73f2720f2ed94c176194041", size = 543060, upload-time = "2026-08-06T14:50:05.15Z" }, + { url = "https://files.pythonhosted.org/packages/f5/18/a21935834a687940ad83ecfc14aa9118493f0da53b6e9861082f8cae2381/librt-0.14.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:62d566b4b4f6510d471fb6fa1b6bf8d183a1039d2c058d85f7481ee24ee3d27d", size = 546840, upload-time = "2026-08-06T14:50:06.571Z" }, + { url = "https://files.pythonhosted.org/packages/e6/d1/98915036feb2315cabd700f25d9915969f81a8391d2cd9c0cc93df6f7116/librt-0.14.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:069a5790f1ba9b6abd882033a486b5a5b68754854b7ad015ee5ad8da1d23e11f", size = 535732, upload-time = "2026-08-06T14:50:08.478Z" }, + { url = "https://files.pythonhosted.org/packages/40/e4/280b07ef374464ca550523ed82049bffe8e06f73d11ee947543389b3cd23/librt-0.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2ec4541a9e522871fa2f2983478d7ee9cd994af1e4718b7e291904c15430b062", size = 573579, upload-time = "2026-08-06T14:50:09.949Z" }, + { url = "https://files.pythonhosted.org/packages/9b/75/773489183b257cab2f341087d9327155f7763c1fab07984a8d748554bdfa/librt-0.14.0-cp312-cp312-win32.whl", hash = "sha256:1697ebe1612604233cd69383c4369c91a40f7d8ad1bd890e1647acec35700f32", size = 106097, upload-time = "2026-08-06T14:50:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7c/f60a3379723295761403ae6301be16afa98b389dee8c6aa1b5de35794d76/librt-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:3e30f225dc2598638a03bd0fd56d479e09263fd769298af57711c2c921498e59", size = 126933, upload-time = "2026-08-06T14:50:12.743Z" }, + { url = "https://files.pythonhosted.org/packages/bc/d5/08147d10a6e5ca676dc0e140b10758a83de73fc863712f167751f2aa8bca/librt-0.14.0-cp312-cp312-win_arm64.whl", hash = "sha256:d6c98dd32e0f8d1a701bcfd470de0d09972d725c8dbad3cf9791b5262caae1a4", size = 112237, upload-time = "2026-08-06T14:50:14.12Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, +] + +[[package]] +name = "micro-diffusion" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "gen-worker" }, + { name = "msgspec" }, + { name = "pillow" }, + { name = "safetensors" }, +] + +[package.dev-dependencies] +dev = [ + { name = "mypy" }, + { name = "pytest" }, +] +local = [ + { name = "torch" }, +] + +[package.metadata] +requires-dist = [ + { name = "gen-worker", specifier = "==0.93.3" }, + { name = "msgspec", specifier = ">=0.18" }, + { name = "pillow" }, + { name = "safetensors", specifier = ">=0.4" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "mypy", specifier = ">=1.10.0" }, + { name = "pytest", specifier = ">=9.0.3" }, +] +local = [{ name = "torch", specifier = ">=2.11.0" }] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "msgspec" +version = "0.21.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/60/f79b9b013a16fa3a58350c9295ddc6789f2e335f36ea61ed10a21b215364/msgspec-0.21.1.tar.gz", hash = "sha256:2313508e394b0d208f8f56892ca9b2799e2561329de9763b19619595a6c0f72c", size = 319193, upload-time = "2026-04-12T21:44:50.394Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/cf/317224852c00248c620a9bcf4b26e2e4ab8afd752f18d2a6ef73ebd423b6/msgspec-0.21.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4248cf0b6129b7d230eacd493c17cc2d4f3989f3bb7f633a928a85b7dcfa251", size = 196188, upload-time = "2026-04-12T21:44:07.181Z" }, + { url = "https://files.pythonhosted.org/packages/6d/81/074612945c0666078f7366f40000013de9f6ba687491d450df699bceebc9/msgspec-0.21.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5102c7e9b3acff82178449b85006d96310e690291bb1ea0142f1b24bcb8aabcb", size = 188473, upload-time = "2026-04-12T21:44:08.736Z" }, + { url = "https://files.pythonhosted.org/packages/8a/37/655101799590bcc5fddb2bd3fe0e6194e816c2d1da7c361725f5eb89a910/msgspec-0.21.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:846758412e9518252b2ac9bffd6f0e54d9ff614f5f9488df7749f81ff5c80920", size = 218871, upload-time = "2026-04-12T21:44:09.917Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d1/d4cd9fe89c7d400d7a18f86ccc94daa3f0927f53558846fcb60791dce5d6/msgspec-0.21.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21995e74b5c598c2e004110ad66ec7f1b8c20bf2bcf3b2de8fd9a3094422d3ff", size = 225025, upload-time = "2026-04-12T21:44:11.191Z" }, + { url = "https://files.pythonhosted.org/packages/24/bf/e20549e602b9edccadeeff98760345a416f9cce846a657e8b18e3396b212/msgspec-0.21.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6129f0cca52992e898fd5344187f7c8127b63d810b2fd73e36fca73b4c6475ee", size = 222672, upload-time = "2026-04-12T21:44:12.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/68/04d7a8f0f786545cf9b8c280c57aa6befb5977af6e884b8b54191cbe44b3/msgspec-0.21.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ef3ec2296248d1f8b9231acb051b6d471dfde8f21819e86c9adaaa9f42918521", size = 227303, upload-time = "2026-04-12T21:44:13.709Z" }, + { url = "https://files.pythonhosted.org/packages/cc/4d/619866af2840875be408047bf9e70ceafbae6ab50660de7134ed1b25eb86/msgspec-0.21.1-cp312-cp312-win_amd64.whl", hash = "sha256:d4ab834a054c6f0cbeef6df9e7e1b33d5f1bc7b86dea1d2fd7cad003873e783d", size = 190017, upload-time = "2026-04-12T21:44:14.977Z" }, + { url = "https://files.pythonhosted.org/packages/5e/2e/a8f9eca8fd00e097d7a9e99ba8a4685db994494448e3d4f0b7f6e9a3c0f7/msgspec-0.21.1-cp312-cp312-win_arm64.whl", hash = "sha256:628aaa35c74950a8c59da330d7e98917e1c7188f983745782027748ee4ca573e", size = 175345, upload-time = "2026-04-12T21:44:16.431Z" }, +] + +[[package]] +name = "mypy" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ast-serialize" }, + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/12/af/4e516a05d3ca2eb9283e9ec45b2c02225c1514dd6da49fd3c9eaa6639370/mypy-2.3.0.tar.gz", hash = "sha256:465965d41cd9a2726694e983e8ce7113259327bec798115d1e1dfa2a52fb666e", size = 3988104, upload-time = "2026-07-13T11:34:53.387Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/94/0e7e592619e2133596a47cdd642534b0456545c218430bd3b9d8fefdd1b1/mypy-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d53fc67b9d28a43c6199077f49fea0f05839e36cf6158500331c9549225e5a5", size = 15026523, upload-time = "2026-07-13T11:34:49.206Z" }, + { url = "https://files.pythonhosted.org/packages/f6/d2/1e1731df090a857df2807177a4626863e5ac0f0256513c35780efe53986f/mypy-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fbc00cee7bdbb9291979ddc9d08034a29dfcda4932628c9bbc28c1edd589df0c", size = 14032189, upload-time = "2026-07-13T11:33:57.168Z" }, + { url = "https://files.pythonhosted.org/packages/44/95/cab921f4a806e171f34113e6181dd23c55358ccf6a80741269ef594a410e/mypy-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04e617030eca5221909c8b7d8d7fd1c637948199aa2100b2ad9813feb07e1491", size = 14198696, upload-time = "2026-07-13T11:32:12.767Z" }, + { url = "https://files.pythonhosted.org/packages/66/80/e6d008bb19fe446e3662d85e0e2717bf9f2d611a2164fb29d6e067dbf46c/mypy-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56c184d2c20ca6b6378d58d1960270a767f41f5e44acbbd27f05effef4f4e1d7", size = 15286904, upload-time = "2026-07-13T11:34:27.594Z" }, + { url = "https://files.pythonhosted.org/packages/db/83/94397c9293608a364aa03e8084fb34ede4ae976a260384b9b52929308135/mypy-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3961a4a34b05f7c74b0f05aa51fbfe99a2d1e126038df40318d15c8f558b7ef3", size = 15528342, upload-time = "2026-07-13T11:34:07.819Z" }, + { url = "https://files.pythonhosted.org/packages/cf/96/d8b37d819adec6cfccfb1fd3afc1735d94717ddeafb45536db9c6943e09b/mypy-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b1942b9314d4c784b8ea1dbab4972603290e5dd5630f06675f13aec97526bc4c", size = 11218346, upload-time = "2026-07-13T11:28:27.745Z" }, + { url = "https://files.pythonhosted.org/packages/2b/cd/cd9f725b19b19e5b530a154cf9bcf9e94279c5d55b3c34fb42b3aa48ea1b/mypy-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:be51653d7669d7d7955d613b8d0bb57d5b652eaf71a873ddf65ac87254dd2595", size = 10204525, upload-time = "2026-07-13T11:31:02.552Z" }, + { url = "https://files.pythonhosted.org/packages/2c/fa/fdc54fe583ba3cafbcedfb70eeeaf03849f75b1827a07096c7bd996f582d/mypy-2.3.0-py3-none-any.whl", hash = "sha256:6b1cdb579446b60432432b2b2403a6201b4b475a004d7f488511c9ba177c9e88", size = 2753292, upload-time = "2026-07-13T11:33:18.48Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "networkx" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, +] + +[[package]] +name = "numpy" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/fd/89965aa4ac08c74998539fcbf24fa3540f3e15237fbeb6bcf9c908f4aade/numpy-2.5.1.tar.gz", hash = "sha256:a48a113e6afea91f5608793bafa7ef2ad481fefbda87ec5069f483de61cb9fa3", size = 20755553, upload-time = "2026-07-04T17:08:00.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/7b/14687aa674250e5e546f616f486b0d56d3631cd5b2415739141ce40bdcea/numpy-2.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c889b56fe48b1018f764b0eec8df59ab654e9148aa91faa12596043500de277", size = 16801574, upload-time = "2026-07-04T17:06:12.423Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/cc5bb2a3f2913d27d6dbb2c78d25921fabaedc6741d4a5a615a11f3c5bf3/numpy-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab451b59c5643c570974c43aef780703ef1d3b4965d2be07afd530615a9358d1", size = 11772250, upload-time = "2026-07-04T17:06:15.726Z" }, + { url = "https://files.pythonhosted.org/packages/42/77/fdf34a71dd30f54979b18603bee915e0aaf825b07afe79acd60b04b691e2/numpy-2.5.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:78798bd5b9ad744056af8efa90e3b9ddaa53272a0848a483084a1cc0a13b2dc0", size = 5331516, upload-time = "2026-07-04T17:06:17.913Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e2/eb7efa015b4cce41e2517bf182a7fce0d7d5b9d9ed76a29bfa0f4fe4505c/numpy-2.5.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2ae0ca40bcb22d6ba59c1dfd5446f49940b0f2d821fde133f10dda11f816b84e", size = 6664863, upload-time = "2026-07-04T17:06:20.02Z" }, + { url = "https://files.pythonhosted.org/packages/a9/4b/a2b32dd94ee9ffbeecb28152240042a3949db33b1c834d44090b80e1b3b8/numpy-2.5.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61ac47e772e6b8ea489e1d2f441a34c5c3ac17327e7ce294cbdf535795ad4e75", size = 15167977, upload-time = "2026-07-04T17:06:21.621Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a9/6e73d68500f80773f65f0654ea932019d6694329a0eb0ed0533de38df376/numpy-2.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59fda5e192b570217ec2580c96f00e9a7e12ef6866a900eb089b62c1a32545ca", size = 16672469, upload-time = "2026-07-04T17:06:24.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/7d/ad3e59015135f5261c95fd4cafeff159c955febd83a99a1d9250c4233815/numpy-2.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f7119ebff1a9829e9f431a4f9d28e703023bb6b9fe7c8f724467dbfc27c94ab3", size = 16527531, upload-time = "2026-07-04T17:06:26.69Z" }, + { url = "https://files.pythonhosted.org/packages/83/d0/a39b2fbcde9cb17a1dac678f254b33a6336298af9df338824c685425d5e8/numpy-2.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e824c2acf8862052246be5a44c15da1777940c60d010dd2aab897824d9c430f9", size = 18431940, upload-time = "2026-07-04T17:06:29.521Z" }, + { url = "https://files.pythonhosted.org/packages/04/12/cff070947791c1ed425ff76413189adbdc2fbe215eba7ce7fa454a03c7f8/numpy-2.5.1-cp312-cp312-win32.whl", hash = "sha256:08d60c810432eb83360958dea0999ac4cfb94531ea8efcbf0b7f277c2068aeb2", size = 6066764, upload-time = "2026-07-04T17:06:32.571Z" }, + { url = "https://files.pythonhosted.org/packages/65/66/53f31807a48a750f9d748da273bc3fcedd12b27ff1f3e373bfec55ef2dc0/numpy-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7d60026c0bdb1380e83bfa7a0419c4577ee4b9a08880afcb6dadeb74c649fa2", size = 12430966, upload-time = "2026-07-04T17:06:34.926Z" }, + { url = "https://files.pythonhosted.org/packages/2b/2a/d1a88066b1c14186f5d3c0d18c94f17b064511982bab0578d49ee9d43c29/numpy-2.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:17a25e09640602e10bc8de0e6fa2b3fd68eedd84ba6d7842dc8f32f9ab87bd0b", size = 10350488, upload-time = "2026-07-04T17:06:37.785Z" }, +] + +[[package]] +name = "nvidia-cublas" +version = "13.1.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cuda-nvrtc" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/a1/0bd24ee8c8d03adac032fd2909426a00c88f8c57961b1277ded97f91119f/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b7a210458267ac818974c53038fbec2e969d5c99f305ab15c72522fa9f001dd5", size = 542848918, upload-time = "2026-04-08T18:46:22.985Z" }, + { url = "https://files.pythonhosted.org/packages/3b/cd/154ca20c38269e05eff77c1464e6c1da89f50a6390b565e9d82e06bc11e1/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:37936a16db8fe4ac1f065c2139360608a543a09275cb1a1af612e08cfa065436", size = 423138758, upload-time = "2026-04-08T18:46:58.655Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti" +version = "13.0.85" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/2a/80353b103fc20ce05ef51e928daed4b6015db4aaa9162ed0997090fe2250/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:796bd679890ee55fb14a94629b698b6db54bcfd833d391d5e94017dd9d7d3151", size = 10310827, upload-time = "2025-09-04T08:26:42.012Z" }, + { url = "https://files.pythonhosted.org/packages/33/6d/737d164b4837a9bbd202f5ae3078975f0525a55730fe871d8ed4e3b952b0/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:4eb01c08e859bf924d222250d2e8f8b8ff6d3db4721288cf35d14252a4d933c8", size = 10715597, upload-time = "2025-09-04T08:26:51.312Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc" +version = "13.0.88" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/68/483a78f5e8f31b08fb1bb671559968c0ca3a065ac7acabfc7cee55214fd6/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:ad9b6d2ead2435f11cbb6868809d2adeeee302e9bb94bcf0539c7a40d80e8575", size = 90215200, upload-time = "2025-09-04T08:28:44.204Z" }, + { url = "https://files.pythonhosted.org/packages/b7/dc/6bb80850e0b7edd6588d560758f17e0550893a1feaf436807d64d2da040f/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d27f20a0ca67a4bb34268a5e951033496c5b74870b868bacd046b1b8e0c3267b", size = 43015449, upload-time = "2025-09-04T08:28:20.239Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime" +version = "13.0.96" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/4f/17d7b9b8e285199c58ce28e31b5c5bbaa4d8271af06a89b6405258245de2/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ef9bcbe90493a2b9d810e43d249adb3d02e98dd30200d86607d8d02687c43f55", size = 2261060, upload-time = "2025-10-09T08:55:15.78Z" }, + { url = "https://files.pythonhosted.org/packages/2e/24/d1558f3b68b1d26e706813b1d10aa1d785e4698c425af8db8edc3dced472/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f82250d7782aa23b6cfe765ecc7db554bd3c2870c43f3d1821f1d18aebf0548", size = 2243632, upload-time = "2025-10-09T08:55:36.117Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu13" +version = "9.20.0.48" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/c5/83384d846b2fd17c44bd499b36c75a45ed4f095fbbb2252294e89cea5c5c/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:e31454ae00094b0c55319d9d15b6fa2fc50a9e1c0f5c8c80fb75258234e731e1", size = 444574296, upload-time = "2026-03-09T19:28:27.751Z" }, + { url = "https://files.pythonhosted.org/packages/6e/5e/edb9c0ae051602c3ccaffe424256463636d639e27d7f302dde9975ef9e7a/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0c45dd8eeb50b603f07995b1b300c62ffe6a1980482b82b3bcf94a4ca9d49304", size = 366173588, upload-time = "2026-03-09T19:29:34.474Z" }, +] + +[[package]] +name = "nvidia-cufft" +version = "12.0.0.61" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2f/7b57e29836ea8714f81e9898409196f47d772d5ddedddf1592eadb8ab743/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c44f692dce8fd5ffd3e3df134b6cdb9c2f72d99cf40b62c32dde45eea9ddad3", size = 214085489, upload-time = "2025-09-04T08:31:56.044Z" }, +] + +[[package]] +name = "nvidia-cufile" +version = "1.15.1.6" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/70/4f193de89a48b71714e74602ee14d04e4019ad36a5a9f20c425776e72cd6/nvidia_cufile-1.15.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08a3ecefae5a01c7f5117351c64f17c7c62efa5fffdbe24fc7d298da19cd0b44", size = 1223672, upload-time = "2025-09-04T08:32:22.779Z" }, + { url = "https://files.pythonhosted.org/packages/ab/73/cc4a14c9813a8a0d509417cf5f4bdaba76e924d58beb9864f5a7baceefbf/nvidia_cufile-1.15.1.6-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:bdc0deedc61f548bddf7733bdc216456c2fdb101d020e1ab4b88d232d5e2f6d1", size = 1136992, upload-time = "2025-09-04T08:32:14.119Z" }, +] + +[[package]] +name = "nvidia-curand" +version = "10.4.0.35" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/72/7c2ae24fb6b63a32e6ae5d241cc65263ea18d08802aaae087d9f013335a2/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:133df5a7509c3e292aaa2b477afd0194f06ce4ea24d714d616ff36439cee349a", size = 61962106, upload-time = "2025-08-04T10:21:41.128Z" }, + { url = "https://files.pythonhosted.org/packages/a5/9f/be0a41ca4a4917abf5cb9ae0daff1a6060cc5de950aec0396de9f3b52bc5/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:1aee33a5da6e1db083fe2b90082def8915f30f3248d5896bcec36a579d941bfc", size = 59544258, upload-time = "2025-08-04T10:22:03.992Z" }, +] + +[[package]] +name = "nvidia-cusolver" +version = "12.0.4.66" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas" }, + { name = "nvidia-cusparse" }, + { name = "nvidia-nvjitlink" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" }, + { url = "https://files.pythonhosted.org/packages/5f/67/cba3777620cdacb99102da4042883709c41c709f4b6323c10781a9c3aa34/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0a759da5dea5c0ea10fd307de75cdeb59e7ea4fcb8add0924859b944babf1112", size = 200941980, upload-time = "2025-09-04T08:33:22.767Z" }, +] + +[[package]] +name = "nvidia-cusparse" +version = "12.6.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" }, + { url = "https://files.pythonhosted.org/packages/fa/18/623c77619c31d62efd55302939756966f3ecc8d724a14dab2b75f1508850/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b3c89c88d01ee0e477cb7f82ef60a11a4bcd57b6b87c33f789350b59759360b", size = 145942937, upload-time = "2025-09-04T08:33:58.029Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu13" +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/e1/cdc1797eadf82d3a9a575a19b33fdc871a97edbec42c00b5b5e914f4aff4/nvidia_cusparselt_cu13-0.8.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4dca476c50bf4780d46cd0bfbd82e2bc10a08e4fef7950917ce8d7578d22a23f", size = 221051344, upload-time = "2025-09-05T18:49:51.289Z" }, + { url = "https://files.pythonhosted.org/packages/34/7d/2661f2fb3ac4302f3a246f5fc030213ac60c1fe0bce84f9783dbd831dbb7/nvidia_cusparselt_cu13-0.8.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:786ce87568c303fadb5afcc7102d454cd3040d75f6f8626f5db460d1871f4dd0", size = 170148586, upload-time = "2025-09-05T18:50:50.248Z" }, +] + +[[package]] +name = "nvidia-nccl-cu13" +version = "2.29.7" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/0d/daf50d44177ee0cbc7ff0a0c91eb5ff676c82be42f9a970bc7597f440c3a/nvidia_nccl_cu13-2.29.7-py3-none-manylinux_2_18_aarch64.whl", hash = "sha256:674a12383e3c38a1bcccae7d4f3633b37852230b6047883cb2f4c2d1b36d9bf5", size = 206014712, upload-time = "2026-03-03T05:34:20.843Z" }, + { url = "https://files.pythonhosted.org/packages/67/f4/58e4e91b6919367c7aafb8e36fce9aad1a3047e536bf7e2fd560927d3a4c/nvidia_nccl_cu13-2.29.7-py3-none-manylinux_2_18_x86_64.whl", hash = "sha256:edd81538446786ec3b73972543e53bb43bcaf0bfc8ef76cb679fcc390ffe136d", size = 205976000, upload-time = "2026-03-03T05:36:24.472Z" }, +] + +[[package]] +name = "nvidia-nvjitlink" +version = "13.3.33" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/ee/580ca6f29dcab0221db8706badca1bbbb084f1975c4d4e83329c3a7e31f0/nvidia_nvjitlink-13.3.33-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:26a6de7fb4c8fdaa7703d3dad720d6d427ddfea5c48a528fd97c11733ad830e5", size = 40742423, upload-time = "2026-05-26T16:54:51.613Z" }, + { url = "https://files.pythonhosted.org/packages/69/30/45414e35ff2eee7db3da037e5707037ccf9d2b5218ffbdb055ea4d5aa98a/nvidia_nvjitlink-13.3.33-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ce48b37dfeb3cb1eae4cf85adacb47d7a6539ea2272870c9a3628ce275c2037e", size = 39168635, upload-time = "2026-05-26T16:54:13.906Z" }, +] + +[[package]] +name = "nvidia-nvshmem-cu13" +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/0f/05cc9c720236dcd2db9c1ab97fff629e96821be2e63103569da0c9b72f19/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dc2a197f38e5d0376ad52cd1a2a3617d3cdc150fd5966f4aee9bcebb1d68fe9", size = 60215947, upload-time = "2025-09-06T00:32:20.022Z" }, + { url = "https://files.pythonhosted.org/packages/3c/35/a9bf80a609e74e3b000fef598933235c908fcefcef9026042b8e6dfde2a9/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:290f0a2ee94c9f3687a02502f3b9299a9f9fe826e6d0287ee18482e78d495b80", size = 60412546, upload-time = "2025-09-06T00:32:41.564Z" }, +] + +[[package]] +name = "nvidia-nvtx" +version = "13.0.85" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/f3/d86c845465a2723ad7e1e5c36dcd75ddb82898b3f53be47ebd429fb2fa5d/nvidia_nvtx-13.0.85-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4936d1d6780fbe68db454f5e72a42ff64d1fd6397df9f363ae786930fd5c1cd4", size = 148047, upload-time = "2025-09-04T08:29:01.761Z" }, + { url = "https://files.pythonhosted.org/packages/a8/64/3708a90d1ebe202ffdeb7185f878a3c84d15c2b2c31858da2ce0583e2def/nvidia_nvtx-13.0.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb7780edb6b14107373c835bf8b72e7a178bac7367e23da7acb108f973f157a6", size = 148878, upload-time = "2025-09-04T08:28:53.627Z" }, +] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "pillow" +version = "12.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" }, + { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" }, + { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" }, + { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" }, + { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" }, + { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" }, + { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" }, + { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "protobuf" +version = "7.35.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/01/9ef0afd7999eb9badb3a768b4aedd78c86d4c65cfaf1958ab276199e76b4/protobuf-7.35.1.tar.gz", hash = "sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a", size = 458717, upload-time = "2026-06-11T21:55:40.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6", size = 433226, upload-time = "2026-06-11T21:55:31.719Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/dfb89eb0e652a1ff073c39a59fb5e3a83cfe9b57a2c83fa6d78270101767/protobuf-7.35.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799", size = 328847, upload-time = "2026-06-11T21:55:34.035Z" }, + { url = "https://files.pythonhosted.org/packages/0f/58/dc12f2cd484951524af6e3382c785869b9b3fb5e52ee95ae23add53ee8f9/protobuf-7.35.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4", size = 344030, upload-time = "2026-06-11T21:55:34.941Z" }, + { url = "https://files.pythonhosted.org/packages/e4/be/5b3cfe508bfab6761414ff944e3366eb13be4fd71efcd69450f89ba39f43/protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4", size = 327130, upload-time = "2026-06-11T21:55:35.921Z" }, + { url = "https://files.pythonhosted.org/packages/d8/bc/6d6c7ba8709c85f8f2c390b2b118d6fb08a783676a572271851bf45a7d22/protobuf-7.35.1-cp310-abi3-win32.whl", hash = "sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30", size = 428945, upload-time = "2026-06-11T21:55:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/0a/19/8d0cb6f20a1ef7b18f1c8986ad5783f22f84cce39c6ce9a6e645ea55192e/protobuf-7.35.1-cp310-abi3-win_amd64.whl", hash = "sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87", size = 439996, upload-time = "2026-06-11T21:55:38.123Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl", hash = "sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9", size = 171659, upload-time = "2026-06-11T21:55:39.155Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "s3transfer" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/43/35e4d8aa320bffe8287fe8f65f578fa2d2db0a64212f0e710dce58267854/s3transfer-0.19.2.tar.gz", hash = "sha256:ba0309fd86be3c27dbf78cdd813c13c5e1df16e5874b99d2535ebbdfb9892993", size = 165592, upload-time = "2026-07-22T19:30:44.432Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl", hash = "sha256:d8168eccca828cbb2cd573675333f3bddd254313a9c42494b84c76b539e8ba25", size = 90216, upload-time = "2026-07-22T19:30:43.251Z" }, +] + +[[package]] +name = "safetensors" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, + { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, + { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, + { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, + { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, + { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, + { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, +] + +[[package]] +name = "setuptools" +version = "83.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/26/f5d29e25ffdb535afef2d35cdb55b325298f96debd670da4c325e08d70f4/setuptools-83.0.0.tar.gz", hash = "sha256:025bccbbf0fa05b6192bc64ae1e7b16e001fd6d6d4d5de03c97b1c1ade523bef", size = 1154254, upload-time = "2026-07-04T15:31:22.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl", hash = "sha256:29b23c360f22f414dc7336bb39178cc7bcbf6021ed2733cde173f09dba19abb3", size = 1008090, upload-time = "2026-07-04T15:31:20.885Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, +] + +[[package]] +name = "tomli-w" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, +] + +[[package]] +name = "torch" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-bindings", marker = "sys_platform == 'linux'" }, + { name = "cuda-toolkit", extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "sys_platform == 'linux'" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cudnn-cu13", marker = "sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu13", marker = "sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu13", marker = "sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu13", marker = "sys_platform == 'linux'" }, + { name = "setuptools" }, + { name = "sympy" }, + { name = "triton", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/3a/ed0f4d4d1dcde03bced7aac9a28e800abcdc0cbd06b6775044c9fbd877b7/torch-2.13.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2fe228aba290d14b9f31b049be550dbd469c3fd3013d7a19705b30454da97027", size = 111213045, upload-time = "2026-07-08T16:05:22.997Z" }, + { url = "https://files.pythonhosted.org/packages/df/a9/f6a2a4d763ff1df02e9a64c477029db614295bc9367f4131223791ccc243/torch-2.13.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:572df8be8ffb4599c88cbd6a0726f1f854f4da65d2e3c09f0e2c2283333cd6d4", size = 427210998, upload-time = "2026-07-08T16:04:37.708Z" }, + { url = "https://files.pythonhosted.org/packages/f3/82/fea946351658e6534db52d2cc12bc53087cbf87f9440c5f180f367c1950b/torch-2.13.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:796633c4cdf0fe2cdced72d8f88f22e73dbcfce83132763162f6d4bff13b820b", size = 526605292, upload-time = "2026-07-08T16:04:22.81Z" }, + { url = "https://files.pythonhosted.org/packages/21/d6/e8f3c6f7e01f626f77259de9860d2a78bc84c40539e28e79b7e98b0bb659/torch-2.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:024c6cc0c1b085f2f91f20a3dc27b0471d021c31ce84b81be3afdc39f791fd9d", size = 122057313, upload-time = "2026-07-08T16:03:53.43Z" }, +] + +[[package]] +name = "tqdm" +version = "4.70.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/3b/6c24bec5be5e743ffd99576daa5cc077722fc7d5bbc00bd133fa0c698dc6/tqdm-4.70.0.tar.gz", hash = "sha256:55b0b0dbd97462d06ebee91e4dac24ed4d4702be82b24f07e6c1d27e08cea220", size = 795438, upload-time = "2026-07-27T11:33:15.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl", hash = "sha256:7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953", size = 80184, upload-time = "2026-07-27T11:33:13.167Z" }, +] + +[[package]] +name = "triton" +version = "3.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/fa/f856e24deb462d5f18bd4b5a746957862ab9b6ee5834bda60605ec348366/triton-3.7.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9497f2e696ee368862a181a90b2dcc03ca978cc4f602abd67c7d81022a6988e1", size = 184692359, upload-time = "2026-06-17T20:03:48.288Z" }, + { url = "https://files.pythonhosted.org/packages/c4/6f/fb96d15db6f36d6eae4cafb998c2e0353bf59d7c4ea1662d7497f269134a/triton-3.7.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e40869937a68206ec70d7f25bb7ec6433cb083f9135e1f36dbd318dc449a728", size = 197719725, upload-time = "2026-06-17T19:53:20.419Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "wheel" +version = "0.47.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/62/75f18a0f03b4219c456652c7780e4d749b929eb605c098ce3a5b6b6bc081/wheel-0.47.0.tar.gz", hash = "sha256:cc72bd1009ba0cf63922e28f94d9d83b920aa2bb28f798a31d0691b02fa3c9b3", size = 63854, upload-time = "2026-04-22T15:51:27.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl", hash = "sha256:212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced", size = 32218, upload-time = "2026-04-22T15:51:26.296Z" }, +] diff --git a/scripts/micro_mint_rig.py b/scripts/micro_mint_rig.py index 05fdc0e1..594d21fb 100755 --- a/scripts/micro_mint_rig.py +++ b/scripts/micro_mint_rig.py @@ -82,8 +82,11 @@ #: The size ceiling the policy carve-out states. Enforced, not documented. MAX_WEIGHTS_BYTES = 500 * 1000 * 1000 -ENDPOINT_MODULE = "harness.tiny_diffusion_endpoint" -FUNCTION = "rig-generate" +#: pgw#997: WHAT the rig mints is now a choice. `tiny` is pgw#978's original +#: one-entry plumbing toy; `micro` is the org-worker-shaped +#: `examples/micro-diffusion` package — three export entries, container inputs, +#: generated weights, a Dockerfile. See `tests/harness/rig_vehicles.py`. +DEFAULT_VEHICLE = "tiny" # --------------------------------------------------------------------------- @@ -225,7 +228,7 @@ def report(self) -> str: f"(the number that replaces 4 hours)") -def _mint_slot(tree: Path) -> Any: +def _mint_slot(tree: Path, ref_path: str) -> Any: """The parent's resolution: WHICH checkpoint, and WHERE its bytes are. Built through the real `ModelRef`/`MintSlot` types, because pgw#974's whole @@ -237,13 +240,13 @@ def _mint_slot(tree: Path) -> Any: from gen_worker.mint_process import MintSlot return MintSlot( - ref=ModelRef(source="tensorhub", path="rig/tiny-diffusion", tag="prod"), + ref=ModelRef(source="tensorhub", path=ref_path, tag="prod"), path=str(tree), ) def _mint_request( - workdir: Path, tree: Path, capture: Path, *, + workdir: Path, tree: Path, capture: Path, veh: Any, *, ordinal: int = 0, cap_bytes: int = MINT_VRAM_BYTES, ) -> Any: """Built through `mint_delegate.build_request` — the REAL parent chain. @@ -253,23 +256,17 @@ def _mint_request( """ from gen_worker import mint_delegate from gen_worker.mint_delegate import MintTask - from gen_worker.registry import CompileCell - from harness import tiny_diffusion_endpoint as ep - - cfg = CompileCell( - shapes=(ep.PIXEL_SHAPE,), targets=("unet",), family=ep.FAMILY, - regional=False, text_len=ep.TEXT_LEN, dynamic=(), lora_bucket=0, - guidance_scales=(), text_lens=()) + cfg = veh.compile_cell() pending = SimpleNamespace( - family=ep.FAMILY, cell_key="", recipe=os.environ.get("PGW978_RECIPE", "aot"), cfg=cfg, + family=veh.family, cell_key="", recipe=os.environ.get("PGW978_RECIPE", "aot"), cfg=cfg, capture_dir=capture, target=workdir / "cell.tar.gz", mint_root=workdir) # The key is the REAL one, derived the way the arming brain derives it, so # the child's own recomputation has something to agree with. task = MintTask( pending=pending, pipe=None, - function=FUNCTION, modules=(ENDPOINT_MODULE,), - slots={"pipeline": _mint_slot(tree)}, device=ordinal, + function=veh.function, modules=tuple(veh.modules), + slots={"pipeline": _mint_slot(tree, veh.ref_path)}, device=ordinal, execution_lane="", configs={}) return mint_delegate.build_request( task, workdir=workdir, cap_bytes=cap_bytes) @@ -277,8 +274,14 @@ def _mint_request( def run_cycle( root: Path, *, stage: str = "all", force_load: bool = False, - device: str = "auto", + device: str = "auto", vehicle: str = DEFAULT_VEHICLE, ) -> RigResult: + from harness import rig_vehicles + + veh = rig_vehicles.vehicle(vehicle) + for entry in veh.syspath: + if entry not in sys.path: + sys.path.insert(0, entry) result = RigResult() t0 = time.monotonic() @@ -292,19 +295,20 @@ def run_cycle( leg.facts = {"load1": load1, "host_move_guard": guard, **dev, "mint_vram_bytes": MINT_VRAM_BYTES, "adopt_vram_bytes": ADOPT_VRAM_BYTES} - leg.detail = (f"{dev['device']} {dev['sm']} torch={dev['torch']} " - f"load={load1:.1f} covers={dev['covers']}") + leg.facts["vehicle"] = veh.name + leg.facts["vehicle_covers"] = veh.covers + leg.detail = (f"vehicle={veh.name} {dev['device']} {dev['sm']} " + f"torch={dev['torch']} load={load1:.1f} " + f"covers={dev['covers']}") result.env = leg.facts # -- weights ------------------------------------------------------------- - from harness.tiny_diffusion import ( - SYNTHETIC_RUNTIME_ENV, build_checkpoint, checkpoint_bytes, - ) + from harness.tiny_diffusion import SYNTHETIC_RUNTIME_ENV leg = result.add(Leg("weights")) g0 = time.monotonic() - tree = build_checkpoint(root / "checkpoint") - size = checkpoint_bytes(tree) + tree = veh.build_checkpoint(root / "checkpoint" / veh.name) + size = veh.checkpoint_bytes(tree) if size > MAX_WEIGHTS_BYTES: raise RigRefused( f"generated checkpoint is {size / 1e6:.1f} MB, over the " @@ -320,17 +324,20 @@ def run_cycle( leg = result.add(Leg("handoff")) g0 = time.monotonic() - request = _mint_request(workdir, tree, capture, + request = _mint_request(workdir, tree, capture, veh, ordinal=int(dev["device_ordinal"]), cap_bytes=(MINT_VRAM_BYTES if dev["device_kind"] == "cuda" else 0)) leg.ok, leg.seconds = True, time.monotonic() - g0 + entries = _declared_entries(veh) leg.facts = {"family": request.family, "recipe": request.recipe, "slots": sorted(request.slots), "cell_key": request.cell_key, - "vram_cap_bytes": request.vram_cap_bytes} + "vram_cap_bytes": request.vram_cap_bytes, + "declared_entries": entries} leg.detail = (f"family={request.family} recipe={request.recipe} " - f"slots={sorted(request.slots)}") + f"slots={sorted(request.slots)} " + f"entries={len(entries)}") # -- the child ----------------------------------------------------------- from gen_worker import mint_process as mp @@ -340,7 +347,8 @@ def run_cycle( phases: List[str] = [] env = dict(mp.child_env(request)) env["PYTHONPATH"] = os.pathsep.join( - [str(REPO / "tests"), str(REPO / "src"), env.get("PYTHONPATH", "")]) + [str(REPO / "tests"), str(REPO / "src"), *veh.syspath, + env.get("PYTHONPATH", "")]) env["PGW978_CHECKPOINT"] = str(tree) if dev["device_kind"] != "cuda": # pgw#983: a cell key needs an `sm` and this box can state none. The @@ -372,10 +380,25 @@ def run_cycle( result.total_s = time.monotonic() - t0 return result warm = float((report.phases if report else {}).get("warmup_forward", 0.0)) + from gen_worker import aot_serve as _serve + + packed = sorted( + (_serve.unpack_metadata(Path(outcome.artifact or "")).get("entries") or {})) + leg.facts["packed_entries"] = packed + if entries and sorted(entries) != packed: + # The declaration said N entries; the tarball carries M. A cycle that + # reported green on a cell missing an arm would be the exact silent + # loss the entry vocabulary exists to prevent. + leg.ok = False + leg.detail = (f"declared entries {sorted(entries)!r} but the packed " + f"cell carries {packed!r}") + result.total_s = time.monotonic() - t0 + return result leg.detail = ( f"minted {Path(outcome.artifact or '').name} " f"key={(report.cell_key if report else '')[:20]} " - f"warm={warm:.2f}s peak={leg.facts['peak_vram_bytes'] / 1e9:.2f}GB") + f"warm={warm:.2f}s peak={leg.facts['peak_vram_bytes'] / 1e9:.2f}GB " + f"entries={len(packed)}") if stage == "mint": result.total_s = time.monotonic() - t0 @@ -404,16 +427,23 @@ def run_cycle( leg = result.add(Leg("adopt")) g0 = time.monotonic() adopted = _adopt_in_subprocess( - hub.base, root, + hub.base, root, veh, tree, synthetic_runtime=bool( next(lg for lg in result.legs if lg.name == "mint-child").facts.get("synthetic_runtime"))) leg.seconds = time.monotonic() - g0 leg.ok = bool(adopted.get("ok")) leg.facts = adopted + parity = adopted.get("parity_max_abs") leg.detail = ( - f"pid={adopted.get('pid')} adopted {str(adopted.get('cell_key'))[:20]} " - f"({adopted.get('artifact_bytes', 0) / 1e6:.1f} MB)" + f"pid={adopted.get('pid')} adopted " + f"{str(adopted.get('cell_key'))[:20]} " + f"({adopted.get('artifact_bytes', 0) / 1e6:.1f} MB" + + (f", {len(adopted['entries'])} entries" + if adopted.get("entries") else "") + ")" + + (f" parity max|delta|=" + f"{max(parity.values()):.2e} over {len(parity)} arms" + if parity else "") if leg.ok else (str(adopted.get("error") or adopted.get("miss_log") or "")[-400:])) finally: @@ -442,39 +472,26 @@ def _publish(hub: Any, request: Any, artifact: Path) -> str: return publisher.publish(request.family, artifact, meta) -ADOPT_CHILD = """ -import json, os, sys -sys.path.insert(0, %(tests)r) -sys.path.insert(0, %(src)r) -from pathlib import Path -from types import SimpleNamespace -from gen_worker import aot_cells -from gen_worker.registry import CompileCell -from harness import tiny_diffusion_endpoint as ep -from harness.tiny_diffusion import TinyUNet - -cfg = CompileCell( - shapes=(ep.PIXEL_SHAPE,), targets=("unet",), family=ep.FAMILY, - regional=False, text_len=ep.TEXT_LEN, dynamic=(), lora_bucket=0, - guidance_scales=(), text_lens=()) -pipe = SimpleNamespace(unet=TinyUNet().eval()) -cell = aot_cells.discover( - pipe, cfg, base_url=%(base)r, - worker_jwt=lambda: "local-rig-worker-jwt", - cache_dir=Path(%(cache)r)) -out = {"pid": os.getpid(), "ok": cell is not None} -if cell is not None: - out.update({ - "cell_key": cell.cell_key, "family": cell.family, "ref": cell.ref, - "snapshot_digest": cell.snapshot_digest, - "artifact_bytes": Path(cell.artifact).stat().st_size, - }) -print("RIG_ADOPT " + json.dumps(out)) -""" +def _declared_entries(veh: Any) -> List[str]: + """The entry names this vehicle's declaration says to mint. + + Reported by the handoff leg so a cycle states its own SIZE: the whole + point of the micro vehicle is that this list has three rows and sdxl's + has thirty-six. A vehicle whose family carries no declaration (the + dynamo-recipe toy) reports none rather than failing. + """ + from gen_worker import aot_declaration as ad + from gen_worker.api.export_contract import export_declaration + + decl = export_declaration(veh.family) + if decl is None: + return [] + return [ad.plan_entry_name(p) for p in ad.cell_plans(decl)] def _adopt_in_subprocess( - base: str, root: Path, *, synthetic_runtime: bool = False, + base: str, root: Path, veh: Any, tree: Path, *, + synthetic_runtime: bool = False, ) -> Dict[str, Any]: """A SECOND OS process doing the discovery. @@ -483,16 +500,19 @@ def _adopt_in_subprocess( nothing but the hub and the card. A fresh interpreter is the cheapest honest stand-in for the second pod. """ - cache = root / "adopt-cache" + cache = root / "adopt-cache" / veh.name cache.mkdir(parents=True, exist_ok=True) - src = ADOPT_CHILD % { - "tests": str(REPO / "tests"), "src": str(REPO / "src"), - "base": base, "cache": str(cache)} + src = veh.adopt_source(base, cache) from harness.tiny_diffusion import SYNTHETIC_RUNTIME_ENV env = dict(os.environ) env["PYTHONPATH"] = os.pathsep.join( - [str(REPO / "tests"), str(REPO / "src"), env.get("PYTHONPATH", "")]) + [str(REPO / "tests"), str(REPO / "src"), *veh.syspath, + env.get("PYTHONPATH", "")]) + # The SAME generated tree the mint traced. Deterministic weights are what + # make that a re-derivation rather than a copy: a second pod with the seed + # has the bytes, and the snapshot digest agrees without a download. + env["PGW978_CHECKPOINT"] = str(tree) if synthetic_runtime: # The adopting side runs `aot_serve.verify`, which compares the cell's # stamped sm/torch/cuda against THIS runtime's. A second process that @@ -547,6 +567,11 @@ def main(argv: Optional[List[str]] = None) -> int: help="auto falls back to CPU and SAYS SO; cuda refuses instead") parser.add_argument("--clean", action="store_true", help="discard the scratch root first") + parser.add_argument( + "--vehicle", default=os.environ.get("PGW997_VEHICLE", DEFAULT_VEHICLE), + help="WHAT to mint: 'tiny' (pgw#978's one-entry plumbing toy) or " + "'micro' (pgw#997's org-worker-shaped examples/micro-diffusion — " + "3 entries, container inputs, generated weights)") args = parser.parse_args(list(argv) if argv is not None else None) root = Path(args.root) @@ -556,7 +581,7 @@ def main(argv: Optional[List[str]] = None) -> int: try: result = run_cycle(root, stage=args.stage, force_load=args.force_load, - device=args.device) + device=args.device, vehicle=args.vehicle) except RigRefused as exc: print(f"REFUSED: {exc}", file=sys.stderr) return 2 diff --git a/tests/harness/rig_runtime.py b/tests/harness/rig_runtime.py new file mode 100644 index 00000000..179c42e6 --- /dev/null +++ b/tests/harness/rig_runtime.py @@ -0,0 +1,29 @@ +"""pgw#997: the rig's synthetic-runtime hook, as a MODULE of its own. + +The micro-diffusion endpoint under ``examples/`` is a REAL org worker and must +carry no rig-only code — a fixture that edits the thing it measures is not a +fixture. But the mint child is a fresh interpreter whose only hook is +``MintRequest.modules``, and on a cardless box the seal needs an ``sm`` +(pgw#983). + +So the rig lists this module FIRST in ``modules`` and the endpoint SECOND. +Discovery imports both, finds its endpoints in the second, and the probe +patch has already happened. Nothing in ``micro_diffusion`` knows the rig +exists. +""" + +from __future__ import annotations + +from harness.tiny_diffusion import ( + SYNTHETIC_RUNTIME, + SYNTHETIC_RUNTIME_ENV, + install_synthetic_runtime_if_asked, +) + +SYNTHETIC_RUNTIME_INSTALLED = install_synthetic_runtime_if_asked() + +__all__ = [ + "SYNTHETIC_RUNTIME", + "SYNTHETIC_RUNTIME_ENV", + "SYNTHETIC_RUNTIME_INSTALLED", +] diff --git a/tests/harness/rig_vehicles.py b/tests/harness/rig_vehicles.py new file mode 100644 index 00000000..034d8db8 --- /dev/null +++ b/tests/harness/rig_vehicles.py @@ -0,0 +1,307 @@ +"""pgw#997: what the micro-mint rig MINTS, as a selectable vehicle. + +The rig (pgw#978) was written against one toy endpoint living in this harness +directory. That endpoint proved the machinery, but it is not an org worker: it +declares one target, one graph class and therefore ONE export entry, and it is +authored inside the SDK's own test tree rather than as a package a build could +consume. + +pgw#997 adds a second vehicle — ``examples/micro-diffusion``, a real +org-worker-shaped package with its own ``pyproject.toml``, ``endpoint.toml``, +Dockerfile and deterministic weight generation. Choosing between them is a rig +flag, so the cheap plumbing vehicle stays available and the endpoint-shaped one +is what a mint-path change is proven against. + +A vehicle answers six questions and nothing else: + + which modules the mint child imports, and which function it warms + where its checkpoint comes from (always GENERATED, never fetched) + which ``CompileCell`` the parent hands across the delegation boundary + which hub ref names the checkpoint + which sys.path entries both interpreters need + how a SECOND process rebuilds enough pipeline to adopt the cell +""" + +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Callable, Dict, Tuple + +REPO = Path(__file__).resolve().parent.parent.parent +MICRO_SRC = REPO / "examples" / "micro-diffusion" / "src" + +#: Listed FIRST in every vehicle's modules: it installs the cardless-box +#: runtime probes before the endpoint module is imported. See rig_runtime. +RUNTIME_HOOK = "harness.rig_runtime" + + +@dataclass(frozen=True) +class Vehicle: + name: str + #: Import names handed to the mint child, in order. + modules: Tuple[str, ...] + #: The routable function the child warms. + function: str + family: str + #: The hub ref the parent's ``MintSlot`` claims. + ref_path: str + #: Extra sys.path entries the parent and BOTH children need. + syspath: Tuple[str, ...] + #: (root) -> the generated checkpoint tree. + build_checkpoint: Callable[[Path], Path] + #: (tree) -> total bytes on disk. + checkpoint_bytes: Callable[[Path], int] + #: () -> the ``registry.CompileCell`` the delegation boundary carries. + compile_cell: Callable[[], Any] + #: (base_url, cache_dir) -> python source for the adopting process. + adopt_source: Callable[[str, Path], str] + #: What this vehicle proves that the other does not — printed, so a + #: reported cycle time is never read against the wrong vehicle. + covers: str + + +# --------------------------------------------------------------------------- +# tiny — the pgw#978 plumbing vehicle. One target, one entry, no packaging. +# --------------------------------------------------------------------------- + + +def _tiny_cell() -> Any: + from gen_worker.registry import CompileCell + + from harness import tiny_diffusion_endpoint as ep + + return CompileCell( + shapes=(ep.PIXEL_SHAPE,), targets=("unet",), family=ep.FAMILY, + regional=False, text_len=ep.TEXT_LEN, dynamic=(), lora_bucket=0, + guidance_scales=(), text_lens=()) + + +_TINY_ADOPT = """ +import json, os, sys +sys.path.insert(0, %(tests)r) +sys.path.insert(0, %(src)r) +from pathlib import Path +from types import SimpleNamespace +from gen_worker import aot_cells +from gen_worker.registry import CompileCell +from harness import tiny_diffusion_endpoint as ep +from harness.tiny_diffusion import TinyUNet + +cfg = CompileCell( + shapes=(ep.PIXEL_SHAPE,), targets=("unet",), family=ep.FAMILY, + regional=False, text_len=ep.TEXT_LEN, dynamic=(), lora_bucket=0, + guidance_scales=(), text_lens=()) +pipe = SimpleNamespace(unet=TinyUNet().eval()) +cell = aot_cells.discover( + pipe, cfg, base_url=%(base)r, + worker_jwt=lambda: "local-rig-worker-jwt", + cache_dir=Path(%(cache)r)) +out = {"pid": os.getpid(), "ok": cell is not None} +if cell is not None: + out.update({ + "cell_key": cell.cell_key, "family": cell.family, "ref": cell.ref, + "snapshot_digest": cell.snapshot_digest, + "artifact_bytes": Path(cell.artifact).stat().st_size, + }) +print("RIG_ADOPT " + json.dumps(out)) +""" + + +def _tiny_adopt_source(base: str, cache: Path) -> str: + return _TINY_ADOPT % { + "tests": str(REPO / "tests"), "src": str(REPO / "src"), + "base": base, "cache": str(cache)} + + +def _tiny_checkpoint(root: Path) -> Path: + from harness.tiny_diffusion import build_checkpoint + + return build_checkpoint(root) + + +def _tiny_checkpoint_bytes(tree: Path) -> int: + from harness.tiny_diffusion import checkpoint_bytes + + return checkpoint_bytes(tree) + + +TINY = Vehicle( + name="tiny", + modules=(RUNTIME_HOOK, "harness.tiny_diffusion_endpoint"), + function="rig-generate", + family="microrig", + ref_path="rig/tiny-diffusion", + syspath=(), + build_checkpoint=_tiny_checkpoint, + checkpoint_bytes=_tiny_checkpoint_bytes, + compile_cell=_tiny_cell, + adopt_source=_tiny_adopt_source, + covers="plumbing: one target, one entry, no container inputs, no packaging", +) + + +# --------------------------------------------------------------------------- +# micro — the pgw#997 org-worker vehicle. Three entries, container inputs. +# --------------------------------------------------------------------------- + + +def _micro_cell() -> Any: + from gen_worker.registry import CompileCell + + from micro_diffusion.aot_declaration import COND_LEN, PIXEL_ROWS + + return CompileCell( + shapes=PIXEL_ROWS, targets=("denoiser", "decoder"), + family="micro-diffusion", regional=False, text_len=COND_LEN, + dynamic=(), lora_bucket=0, guidance_scales=(), text_lens=()) + + +_MICRO_ADOPT = ''' +import json, logging, os, sys +for p in %(paths)r: + sys.path.insert(0, p) +# A MISS is not a crash and its reason lives in the typed `aot-cells` events. +# Without a configured handler they go nowhere and the rig reports "no cell" +# for a filter that rejected twelve of them on one axis (pgw#824). +logging.basicConfig(level=logging.INFO, stream=sys.stderr) +# The SAME runtime hook the mint child imported. `aot_serve.verify` compares +# the cell's stamped sm/torch/cuda against THIS runtime's, so a second process +# that did not get the same supplied probes rejects the cell the first one just +# minted — and reports it as a filter miss, which is the wrong diagnosis. +import harness.rig_runtime # noqa: F401 +import torch +from pathlib import Path +from gen_worker import aot_cells, aot_serve +from gen_worker.registry import CompileCell +from micro_diffusion.aot_declaration import ( + CFG_ARITY, COND_LEN, PIXEL_ROWS, TOKEN_ROWS) +from micro_diffusion.pipeline import MicroPipeline + +torch.set_num_threads(2) +cfg = CompileCell( + shapes=PIXEL_ROWS, targets=("denoiser", "decoder"), + family="micro-diffusion", regional=False, text_len=COND_LEN, + dynamic=(), lora_bucket=0, guidance_scales=(), text_lens=()) +# The adopting process rebuilds the pipeline from the SAME generated tree, +# which is the whole point of deterministic weights: a second machine with the +# seed has the bytes, and the snapshot digest agrees without a download. +pipe = MicroPipeline.from_pretrained(os.environ["PGW978_CHECKPOINT"]) +config = pipe.config + + +def _feed(arity, tokens): + """One legal call of each declared arm, built from a FIXED generator so + the eager pass and the served pass see identical bytes.""" + gen = torch.Generator().manual_seed(997) + x = [torch.randn(tokens, config.in_channels, generator=gen) + for _ in range(arity)] + t = torch.full((arity,), 100.0) + cond = [torch.randn(COND_LEN, config.cond_dim, generator=gen) + for _ in range(arity)] + lat = torch.randn(1, tokens, config.in_channels, generator=gen) + return x, t, cond, lat + + +# ARMS: every declared entry. The rows deliberately differ from the seed row +# the mint traced, so the artifact is exercised through its DERIVED range +# rather than at the one coordinate it was built at. +ARMS = [("denoiser/cfg=true", CFG_ARITY, TOKEN_ROWS[0]), + ("denoiser/cfg=false", 1, TOKEN_ROWS[0]), + ("decoder", 1, TOKEN_ROWS[-1])] + +eager = {} +with torch.no_grad(): + for name, arity, latent in ARMS: + x, t, cond, lat = _feed(arity, latent) + eager[name] = (pipe.decoder(lat) if name == "decoder" + else pipe.denoiser(x, t, cond)).clone() + +cell = aot_cells.discover( + pipe, cfg, base_url=%(base)r, + worker_jwt=lambda: "local-rig-worker-jwt", + cache_dir=Path(%(cache)r)) +out = {"pid": os.getpid(), "ok": cell is not None} +if cell is not None: + meta = aot_serve.unpack_metadata(Path(cell.artifact)) + out.update({ + "cell_key": cell.cell_key, "family": cell.family, "ref": cell.ref, + "snapshot_digest": cell.snapshot_digest, + "artifact_bytes": Path(cell.artifact).stat().st_size, + "entries": sorted((meta.get("entries") or {})), + }) + # PARITY. Adoption that is never CALLED proves the filter, not the cell — + # and the serve-side call is exactly where pgw#994 lives: a container + # input expands to N leaves and every contract position after it shifts. + outcome = aot_serve.enable(pipe, cfg, Path(%(cache)r), Path(cell.artifact)) + out["armed"] = bool(outcome) + out["arm_detail"] = str(getattr(outcome, "detail", "") or + getattr(outcome, "reason", ""))[:400] + if outcome: + deltas = {} + with torch.no_grad(): + for name, arity, latent in ARMS: + x, t, cond, lat = _feed(arity, latent) + got = (pipe.decoder(lat) if name == "decoder" + else pipe.denoiser(x, t, cond)) + deltas[name] = float((got - eager[name]).abs().max()) + out["parity_max_abs"] = deltas + out["served_entry_calls"] = dict(aot_serve.served_entry_calls(pipe)) + out["execution_count"] = int(aot_serve.execution_count(pipe)) + out["ingress_refusals"] = int(aot_serve.ingress_refusals(pipe)) + # A tolerance, not equality: AOTI fuses and reassociates, so bitwise + # identity is not the claim. 1e-4 on float32 activations is. + out["parity_ok"] = all(v <= 1e-4 for v in deltas.values()) + out["ok"] = bool(out["parity_ok"]) and out["execution_count"] > 0 +print("RIG_ADOPT " + json.dumps(out)) +''' + + +def _micro_adopt_source(base: str, cache: Path) -> str: + return _MICRO_ADOPT % { + "paths": [str(REPO / "tests"), str(REPO / "src"), str(MICRO_SRC)], + "base": base, "cache": str(cache)} + + +def _micro_checkpoint(root: Path) -> Path: + from micro_diffusion.weights import materialize + + return materialize(root) + + +def _micro_checkpoint_bytes(tree: Path) -> int: + from micro_diffusion.weights import tree_bytes + + return tree_bytes(tree) + + +MICRO = Vehicle( + name="micro", + modules=(RUNTIME_HOOK, "micro_diffusion.main"), + function="generate", + family="micro-diffusion", + ref_path="cozy/micro-diffusion", + syspath=(str(MICRO_SRC),), + build_checkpoint=_micro_checkpoint, + checkpoint_bytes=_micro_checkpoint_bytes, + compile_cell=_micro_cell, + adopt_source=_micro_adopt_source, + covers=("org-worker packaging: 3 export entries (2 fork arms + a second " + "target), CONTAINER inputs with a plain input after them " + "(pgw#993/pgw#994), a derived dynamic range, generated weights"), +) + + +VEHICLES: Dict[str, Vehicle] = {v.name: v for v in (TINY, MICRO)} +DEFAULT_VEHICLE = TINY.name + + +def vehicle(name: str) -> Vehicle: + try: + return VEHICLES[str(name)] + except KeyError: + raise SystemExit( + f"unknown rig vehicle {name!r} (known: {sorted(VEHICLES)!r})") + + +__all__ = ["DEFAULT_VEHICLE", "MICRO", "TINY", "VEHICLES", "Vehicle", "vehicle"] diff --git a/tests/test_micro_endpoint_pgw997.py b/tests/test_micro_endpoint_pgw997.py new file mode 100644 index 00000000..ece20bf0 --- /dev/null +++ b/tests/test_micro_endpoint_pgw997.py @@ -0,0 +1,255 @@ +"""pgw#997 — the micro-diffusion endpoint, asserted where CI can see it. + +The full mint cycle needs a compiler and is LOCAL-ONLY (pgw#978's rig). What +does NOT need one is every claim this family makes about its own SHAPE, and +those are the claims that would rot silently: the entry count, the container +ordering that keeps pgw#993/pgw#994 under test, the determinism of the +generated weights, and the two model properties the declaration's strategy +depends on. + +Each test below is written so it goes RED if the property it names stops +holding — not so it passes. +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +import pytest +import torch + +from harness.rig_vehicles import MICRO_SRC + +if str(MICRO_SRC) not in sys.path: + sys.path.insert(0, str(MICRO_SRC)) + +from micro_diffusion import aot_declaration as decl_mod # noqa: E402 +from micro_diffusion.main import Generate, Size # noqa: E402 +from micro_diffusion.model import ( # noqa: E402 + MicroConfig, + MicroDecoder, + MicroDenoiser, +) +from micro_diffusion.pipeline import MicroPipeline # noqa: E402 +from micro_diffusion.weights import ( # noqa: E402 + MAX_TREE_BYTES, + SEED, + load_state, + materialize, + state_dict, + tree_bytes, +) + +from gen_worker import aot_declaration as ad # noqa: E402 +from gen_worker import aot_flatten # noqa: E402 +from gen_worker.aot_mint import ExportSpec # noqa: E402 + +EXPECTED_ENTRIES = ["decoder", "denoiser/cfg=false", "denoiser/cfg=true"] + + +@pytest.fixture(scope="module") +def declaration(): + return decl_mod.build_declaration() + + +@pytest.fixture(scope="module") +def tree(tmp_path_factory) -> Path: + return materialize(tmp_path_factory.mktemp("micro-weights")) + + +# --------------------------------------------------------------------------- +# The size claim — three entries, and the reason it is three +# --------------------------------------------------------------------------- + + +def test_declares_exactly_three_entries(declaration) -> None: + """The whole premise. sdxl declares 36 and costs ~95 min a cycle.""" + names = sorted(ad.plan_entry_name(p) for p in ad.cell_plans(declaration)) + assert names == EXPECTED_ENTRIES + + +def test_the_two_latent_rows_collapse_rather_than_multiply(declaration) -> None: + """Two declared rows, still one artifact per arm — with a DERIVED range. + + If this collapsed the other way the family would have 6 entries, and if + the range were not derived the artifact would silently serve only its + seed row. + """ + assert len(declaration.shapes) == 2 + for plan in ad.cell_plans(declaration): + assert len(plan.rows) == 2, ad.plan_entry_name(plan) + spans = {(d.input_name, d.axis): (d.min, d.max) for d in plan.dynamic} + assert spans, ( + f"{ad.plan_entry_name(plan)} collapsed two rows with NO dynamic " + f"dim — the artifact would silently serve only its seed row") + assert set(spans.values()) == {(1024, 2304)} + + +def test_every_traced_extent_is_linear_in_one_symbol(declaration) -> None: + """pgw#998, kept RED-able. A matmul extent that is a PRODUCT of two + dynamic axes cannot be lowered after the mint's own + ``torch.export.save``/``load`` hand-off to its compile child. The + declaration avoids it by taking token sequences, and this test fails if a + later edit puts two dynamic axes back on one input.""" + for plan in ad.cell_plans(declaration): + per_input: dict = {} + for row in plan.dynamic: + per_input.setdefault(row.input_name, []).append(row.axis) + for name, axes in per_input.items(): + assert len(axes) == 1, ( + f"{ad.plan_entry_name(plan)}/{name} has SYMBOLIC axes {axes} " + f"— their product is a nonlinear traced extent, which " + f"inductor cannot lower after the mint's export save/load " + f"(pgw#998)") + + +def test_the_decoder_is_a_second_target_with_its_own_dims(declaration) -> None: + """A dim carried through a CONTAINER for one target and a PLAIN tensor for + the other — pgw#993's seam, declared.""" + assert declaration.targets == ("denoiser", "decoder") + by_name = {d.name: d for d in declaration.dims} + assert ("x", 0) in by_name["T"].carried_by + assert ("latent", 1) in by_name["T"].carried_by + denoiser = [d for d in ad.cell_plans(declaration) + if d.target == "denoiser"] + decoder = [d for d in ad.cell_plans(declaration) if d.target == "decoder"] + assert len(denoiser) == 2 and len(decoder) == 1 + + +# --------------------------------------------------------------------------- +# The pgw#993 / pgw#994 shape — present, not merely intended +# --------------------------------------------------------------------------- + + +def _spec(target: str, cfg=None) -> ExportSpec: + fork = () if cfg is None else (("cfg", cfg),) + return ExportSpec(family=decl_mod.FAMILY, target=target, fork=fork, + class_dims=()) + + +@pytest.mark.parametrize("cfg,arity", [(True, 2), (False, 1)]) +def test_container_arity_follows_the_fork(declaration, cfg, arity) -> None: + module = MicroDenoiser(MicroConfig()) + got = ad.container_arities(declaration, _spec("denoiser", cfg), module) + assert got == {"x": arity, "cond": arity} + + +def test_a_plain_input_sits_after_a_container_and_its_leaf_shifts( + declaration, +) -> None: + """THE pgw#994 shape, asserted structurally rather than believed. + + ``t`` is argument 1 of the traced call. Once ``x`` expands to two leaves, + ``t``'s FLATTENED position is 2. A serve side that matched the contract's + flattened position against pre-flattening args would bind the whole list + to element 0 and shift ``t`` — which is the defect. This test fails the + day the declaration stops reproducing that divergence. + """ + module = MicroDenoiser(MicroConfig()) + args, kwargs = ad.declared_inputs(module, _spec("denoiser", True), + declaration) + assert kwargs == {} + assert isinstance(args[0], list) and len(args[0]) == 2, "x is a container" + assert isinstance(args[1], torch.Tensor), "t is plain, and it is next" + leaves = aot_flatten.flatten_call(("x", "t", "cond"), args, {}) + by_name = {leaf.name: leaf for leaf in leaves} + t_leaf = by_name["t"] + assert t_leaf.param_position == 1, "argument position" + assert leaves.index(t_leaf) == 2, "flattened position — the divergence" + assert by_name["x.0"].exported_name == "x_0" + + +def test_the_turbo_arm_is_a_one_element_container_not_a_bare_tensor( + declaration, +) -> None: + """A one-element container is ``x_0``, never ``x`` — the arity-1 case is + where a "container support" implementation usually quietly degrades.""" + module = MicroDenoiser(MicroConfig()) + args, _ = ad.declared_inputs(module, _spec("denoiser", False), declaration) + assert isinstance(args[0], list) and len(args[0]) == 1 + leaves = aot_flatten.flatten_call(("x", "t", "cond"), args, {}) + assert leaves[0].exported_name == "x_0" + + +def test_every_declared_arm_runs_eagerly(declaration, tree) -> None: + """The declared example feed is a LEGAL call of the real module — the + cheapest possible catch for a declaration that drifted from its model.""" + pipe = MicroPipeline.from_pretrained(str(tree)) + for target, cfg in (("denoiser", True), ("denoiser", False), + ("decoder", None)): + module = getattr(pipe, target) + args, _ = ad.declared_inputs(module, _spec(target, cfg), declaration) + with torch.no_grad(): + out = module(*args) + assert out.shape[0] > 0 + + +# --------------------------------------------------------------------------- +# The model properties the declaration DEPENDS on +# --------------------------------------------------------------------------- + + +def test_the_graph_is_conv_free(declaration) -> None: + """``dynamic-collapse`` is ratified for conv-free graphs (#730). A conv + added later would make the declared strategy wrong, silently.""" + assert declaration.shape_strategy == "dynamic-collapse" + config = MicroConfig() + for module in (MicroDenoiser(config), MicroDecoder(config)): + convs = [type(m).__name__ for m in module.modules() + if isinstance(m, torch.nn.modules.conv._ConvNd)] + assert convs == [] + + +def test_the_frequency_table_is_a_buffer_not_a_plain_attribute() -> None: + """pgw#857: a plain attribute is lifted as a graph LITERAL and its bytes + ship inside every compiled cell.""" + embed = MicroDenoiser(MicroConfig()).time_embed + assert "freqs" in dict(embed.named_buffers()) + assert "freqs" not in embed.__dict__ + + +# --------------------------------------------------------------------------- +# Generated weights — the locality claim +# --------------------------------------------------------------------------- + + +def test_weights_are_deterministic_and_small(tree, tmp_path) -> None: + again = materialize(tmp_path / "again") + first, second = load_state(tree), load_state(again) + assert sorted(first) == sorted(second) + for name, tensor in first.items(): + assert torch.equal(tensor, second[name]), name + size = tree_bytes(tree) + assert 0 < size <= MAX_TREE_BYTES + assert size < 5_000_000, f"{size} bytes — the family must stay tiny" + + +def test_regenerating_reproduces_the_written_bytes(tree) -> None: + """The claim the Dockerfile's ``--verify`` step enforces at build time.""" + on_disk = load_state(tree) + fresh = state_dict(MicroConfig(), seed=SEED) + assert sorted(on_disk) == sorted(fresh) + for name, tensor in fresh.items(): + assert torch.equal(tensor, on_disk[name]), name + + +# --------------------------------------------------------------------------- +# The endpoint declaration — sdxl's slot shape, which is pgw#969's shape +# --------------------------------------------------------------------------- + + +def test_the_slot_is_a_catalog_slot_with_no_code_default() -> None: + spec = Generate.__gen_worker_endpoint__ + slot = spec.slots["pipeline"] + assert slot.selected_by == "model" + assert slot.default_checkpoint is None + assert slot.pipeline_cls is MicroPipeline + assert spec.resources.gpu is True + + +def test_both_fork_arms_have_a_served_method() -> None: + """A declared arm no function reaches is an entry nothing can ever call.""" + assert callable(Generate.generate) + assert callable(Generate.generate_turbo) + assert [s.value for s in Size] == ["256x256", "384x384"] diff --git a/tests/test_micro_mint_rig_pgw978.py b/tests/test_micro_mint_rig_pgw978.py index 859f3bc5..1d56ccca 100644 --- a/tests/test_micro_mint_rig_pgw978.py +++ b/tests/test_micro_mint_rig_pgw978.py @@ -157,12 +157,16 @@ def test_the_request_the_rig_hands_the_child_carries_a_resolved_slot( import msgspec from gen_worker.mint_process import MintRequest + from harness.rig_vehicles import TINY from harness.tiny_diffusion import build_checkpoint rig = _rig() tree = build_checkpoint(tmp_path / "ckpt") + # pgw#997: the vehicle is now an explicit argument — WHAT the rig mints is + # a choice, so the handoff cannot read it off a module global. request = rig._mint_request( - tmp_path / "mint", tree, tmp_path / "capture", ordinal=-1, cap_bytes=0) + tmp_path / "mint", tree, tmp_path / "capture", TINY, + ordinal=-1, cap_bytes=0) # The boundary IS a JSON file, so round-trip it the way the child will. raw = msgspec.json.encode(request) decoded = msgspec.json.decode(raw, type=MintRequest)