3lc-compute-plugin-sdk 0.2.2__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/CHANGELOG.md +9 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/PKG-INFO +14 -11
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/README.md +12 -9
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/docs/index.md +1 -1
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/docs/plugin-guide.md +54 -69
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/pyproject.toml +2 -2
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/asgi_app.py +10 -18
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/contract.py +2 -3
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/job_context.py +6 -11
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/worker.py +5 -5
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/uv.lock +118 -118
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/.github/workflows/ci.yml +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/.github/workflows/docs.yml +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/.github/workflows/release.yml +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/.gitignore +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/CLAUDE.md +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/LICENSE +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/docs/api.md +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/docs/conf.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/docs/package-lock.json +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/docs/package.json +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/docs/requirements.txt +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/__init__.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/contract/plugin-api.d.ts +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/py.typed +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/__init__.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/alias_override_ui.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/alias_ui.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/aliases.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/config_store.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/config_ui.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/data_source_routes.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/data_source_ui.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/generic_job.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/images.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/job_tracker.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/labels.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/modality.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/model_storage.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/naming.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/ui_inject.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/url_utils.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/tests/test_data_source_routes.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/tests/test_import_light.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/tests/test_url_utils.py +0 -0
- {3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/tests/test_worker_gpu_reclaim.py +0 -0
|
@@ -9,6 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
Nothing yet.
|
|
11
11
|
|
|
12
|
+
## [0.2.3] - 2026-08-21
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Docs: the plugin guide and API docstrings describe the single runtime — a plugin runs in
|
|
16
|
+
its own venv behind a worker; the manifest's `isolation` key accepts only `"venv"` (the
|
|
17
|
+
default when absent). The guide's isolation table, the in-tree host exception callout, and
|
|
18
|
+
the `unload` endpoint reference are gone; the dev-workflow section now documents the
|
|
19
|
+
folder-Source + editable-venv + `worker/stop` loop. No code or contract change.
|
|
20
|
+
|
|
12
21
|
## [0.2.2] - 2026-08-18
|
|
13
22
|
|
|
14
23
|
### Added
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: 3lc-compute-plugin-sdk
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Public Python SDK for building 3LC compute-service plugins
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Public Python SDK for building 3LC compute-service plugins.
|
|
5
5
|
Project-URL: Homepage, https://github.com/3lc-ai/3lc-compute-plugin-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/3lc-ai/3lc-compute-plugin-sdk
|
|
7
7
|
Author-email: 3LC <support@3lc.ai>
|
|
@@ -46,13 +46,13 @@ pip install 3lc-compute-plugin-sdk # import name: tlc_plugin_sdk
|
|
|
46
46
|
|
|
47
47
|
- **`ComputePlugin`** — the base class you subclass. Implement `compute` / `get_ui_fragment`;
|
|
48
48
|
job and lifecycle hooks ship as no-op defaults. There is no `register()` to call — a plugin's
|
|
49
|
-
metadata lives in its `[tool.tlc-compute]` manifest, and the
|
|
49
|
+
metadata lives in its `[tool.tlc-compute]` manifest, and the Hub discovers it from there.
|
|
50
50
|
- **`JobContext`** — the surface a long-running job programs against: `progress` / `metric` /
|
|
51
51
|
`log` / `result` for the generic job panel, `emit` for your plugin's own rich UI, and
|
|
52
52
|
cooperative `cancelled`.
|
|
53
53
|
- **The worker** (`python -m tlc_plugin_sdk.worker`) — serves your plugin's Litestar route
|
|
54
|
-
handlers + the generic reserved routes as an ASGI app,
|
|
55
|
-
|
|
54
|
+
handlers + the generic reserved routes as an ASGI app, out-of-process in the plugin's
|
|
55
|
+
own venv.
|
|
56
56
|
- **`tlc_plugin_sdk.shared.*`** — batteries the heavy plugins share: URL-alias registration,
|
|
57
57
|
config storage/UI, the generic-job helpers, image/label/modality utilities, script injection.
|
|
58
58
|
|
|
@@ -65,14 +65,17 @@ format, custom routes, the job model, UI fragment, checklist).
|
|
|
65
65
|
|
|
66
66
|
`tlc_plugin_sdk.SDK_CONTRACT_VERSION` is this package's own version — one source of truth.
|
|
67
67
|
A plugin pins the SDK (`3lc-compute-plugin-sdk>=X,<Y`) and declares the contract it targets via its
|
|
68
|
-
manifest. The
|
|
69
|
-
both sides agree on. Versions are SemVer; see **Status** below for the 0.x stability
|
|
68
|
+
manifest. The compute service implements a contract range, and the SDK version is the shared
|
|
69
|
+
reference both sides agree on. Versions are SemVer; see **Status** below for the 0.x stability
|
|
70
|
+
stance.
|
|
70
71
|
|
|
71
|
-
##
|
|
72
|
+
## How it fits
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
`
|
|
75
|
-
|
|
74
|
+
This SDK sits at the root of the plugin dependency graph. Its only required dependencies are
|
|
75
|
+
`uvicorn` and `litestar`; the `3lc` data plane is an optional extra
|
|
76
|
+
(`3lc-compute-plugin-sdk[shared]`), pulled in only by the `shared.*` helpers. It **never** depends
|
|
77
|
+
on the compute service itself or on any plugin. A plugin built against `tlc_plugin_sdk` alone is
|
|
78
|
+
therefore portable across service versions and runs in its own isolated environment.
|
|
76
79
|
|
|
77
80
|
## Status
|
|
78
81
|
|
|
@@ -20,13 +20,13 @@ pip install 3lc-compute-plugin-sdk # import name: tlc_plugin_sdk
|
|
|
20
20
|
|
|
21
21
|
- **`ComputePlugin`** — the base class you subclass. Implement `compute` / `get_ui_fragment`;
|
|
22
22
|
job and lifecycle hooks ship as no-op defaults. There is no `register()` to call — a plugin's
|
|
23
|
-
metadata lives in its `[tool.tlc-compute]` manifest, and the
|
|
23
|
+
metadata lives in its `[tool.tlc-compute]` manifest, and the Hub discovers it from there.
|
|
24
24
|
- **`JobContext`** — the surface a long-running job programs against: `progress` / `metric` /
|
|
25
25
|
`log` / `result` for the generic job panel, `emit` for your plugin's own rich UI, and
|
|
26
26
|
cooperative `cancelled`.
|
|
27
27
|
- **The worker** (`python -m tlc_plugin_sdk.worker`) — serves your plugin's Litestar route
|
|
28
|
-
handlers + the generic reserved routes as an ASGI app,
|
|
29
|
-
|
|
28
|
+
handlers + the generic reserved routes as an ASGI app, out-of-process in the plugin's
|
|
29
|
+
own venv.
|
|
30
30
|
- **`tlc_plugin_sdk.shared.*`** — batteries the heavy plugins share: URL-alias registration,
|
|
31
31
|
config storage/UI, the generic-job helpers, image/label/modality utilities, script injection.
|
|
32
32
|
|
|
@@ -39,14 +39,17 @@ format, custom routes, the job model, UI fragment, checklist).
|
|
|
39
39
|
|
|
40
40
|
`tlc_plugin_sdk.SDK_CONTRACT_VERSION` is this package's own version — one source of truth.
|
|
41
41
|
A plugin pins the SDK (`3lc-compute-plugin-sdk>=X,<Y`) and declares the contract it targets via its
|
|
42
|
-
manifest. The
|
|
43
|
-
both sides agree on. Versions are SemVer; see **Status** below for the 0.x stability
|
|
42
|
+
manifest. The compute service implements a contract range, and the SDK version is the shared
|
|
43
|
+
reference both sides agree on. Versions are SemVer; see **Status** below for the 0.x stability
|
|
44
|
+
stance.
|
|
44
45
|
|
|
45
|
-
##
|
|
46
|
+
## How it fits
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
`
|
|
49
|
-
|
|
48
|
+
This SDK sits at the root of the plugin dependency graph. Its only required dependencies are
|
|
49
|
+
`uvicorn` and `litestar`; the `3lc` data plane is an optional extra
|
|
50
|
+
(`3lc-compute-plugin-sdk[shared]`), pulled in only by the `shared.*` helpers. It **never** depends
|
|
51
|
+
on the compute service itself or on any plugin. A plugin built against `tlc_plugin_sdk` alone is
|
|
52
|
+
therefore portable across service versions and runs in its own isolated environment.
|
|
50
53
|
|
|
51
54
|
## Status
|
|
52
55
|
|
|
@@ -17,7 +17,7 @@ pip install 3lc-compute-plugin-sdk # import name: tlc_plugin_sdk
|
|
|
17
17
|
against: `progress` / `metric` / `log` / `result`, `emit` for rich UI, and
|
|
18
18
|
cooperative `cancelled`.
|
|
19
19
|
- **The worker** (`python -m tlc_plugin_sdk.worker`) — serves your plugin's Litestar
|
|
20
|
-
route handlers as an ASGI app,
|
|
20
|
+
route handlers as an ASGI app, out-of-process in the plugin's own venv.
|
|
21
21
|
|
|
22
22
|
```{toctree}
|
|
23
23
|
:maxdepth: 2
|
|
@@ -83,11 +83,6 @@ tlc_plugin_my_plugin/ # the default shape: a standalone venv-isolated p
|
|
|
83
83
|
└── ... # All plugin code lives here
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
> **In-tree host exception.** A host may ship plugins inside its own package with
|
|
87
|
-
> `isolation = "host"` and a host-internal entrypoint; those live in the host's source tree
|
|
88
|
-
> and follow its layout. New plugins should use the `venv` + `tlc_plugin_<name>` shape shown
|
|
89
|
-
> above, not the host form.
|
|
90
|
-
|
|
91
86
|
### 2. Write the manifest
|
|
92
87
|
|
|
93
88
|
All metadata lives in a manifest — a standalone `plugin.toml` next to `__init__.py`. The host
|
|
@@ -96,10 +91,10 @@ source of truth for listing, routing, GPU/CPU classification, SocketIO wiring, a
|
|
|
96
91
|
paths. (`read_manifest()` also accepts a `[tool.tlc-compute]` table in a plugin's `pyproject.toml`
|
|
97
92
|
— it checks `plugin.toml` first.)
|
|
98
93
|
|
|
99
|
-
A
|
|
100
|
-
`pyproject.toml` alongside it that declares only its
|
|
94
|
+
A plugin keeps the **same `plugin.toml`** for metadata and adds a separate
|
|
95
|
+
`pyproject.toml` alongside it that declares only its venv's dependencies (no
|
|
101
96
|
`[tool.tlc-compute]` table there) — see the `timm` / `sam3` / `yolo` plugins for the canonical
|
|
102
|
-
layout
|
|
97
|
+
layout.
|
|
103
98
|
|
|
104
99
|
```toml
|
|
105
100
|
# plugin.toml — the single source of truth for this plugin's metadata.
|
|
@@ -127,34 +122,25 @@ quick_action = false # Show in dashboard quick actions?
|
|
|
127
122
|
# group_icon_svg = '<svg ...><rect x="2" y="2" width="12" height="12" rx="2"/></svg>'
|
|
128
123
|
|
|
129
124
|
[runtime]
|
|
130
|
-
isolation = "venv" # venv (
|
|
125
|
+
isolation = "venv" # "venv" is the only value (and the default when absent)
|
|
131
126
|
entrypoint = "tlc_plugin_my_plugin:MyPlugin" # "pkg.module:ClassName"
|
|
132
127
|
requires_gpu = false # drives GPU vs CPU classification
|
|
133
|
-
provision_extra = "my-plugin" #
|
|
128
|
+
provision_extra = "my-plugin" # umbrella extra the host provisions: `uv sync --extra <this>`
|
|
134
129
|
# Optional SocketIO namespace for real-time updates. Defaults to "/<plugin-id>";
|
|
135
130
|
# declare it only to override (the host registers it at startup so a UI can connect;
|
|
136
131
|
# declaring it does NOT mean emitting custom events):
|
|
137
132
|
# socketio_namespace = "/my-plugin"
|
|
138
133
|
```
|
|
139
134
|
|
|
140
|
-
`runtime.provision_extra` is **required for every
|
|
141
|
-
host installs with `uv sync --extra <that-value>`. For first-party
|
|
142
|
-
per-plugin extra in the `3lc-compute-plugins` umbrella `pyproject.toml`.
|
|
143
|
-
declare it — their deps are a subset of the service.)
|
|
144
|
-
|
|
145
|
-
**`isolation` — where the plugin runs (the *only* placement knob).** A plugin
|
|
146
|
-
declares `isolation` and `requires_gpu`; it never picks a queue or names a lane.
|
|
135
|
+
`runtime.provision_extra` is **required for every plugin distributed through an umbrella**:
|
|
136
|
+
it names the extra the host installs with `uv sync --extra <that-value>`. For first-party
|
|
137
|
+
plugins this is a per-plugin extra in the `3lc-compute-plugins` umbrella `pyproject.toml`.
|
|
147
138
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
The plugin class is identical either way — `run_job(ctx)` talks only to `ctx`, so
|
|
154
|
-
the same code runs in-process or in a worker. `requires_gpu = true` routes the job
|
|
155
|
-
through the shared GPU queue (one GPU job at a time, across every plugin);
|
|
156
|
-
`requires_gpu = false` jobs run on the CPU queue. Both are host-owned; the plugin
|
|
157
|
-
never touches a queue.
|
|
139
|
+
Every plugin runs in its own uv-managed venv, behind a worker the host spawns and talks to
|
|
140
|
+
over a Unix socket — the host registers the plugin from its manifest alone and never imports
|
|
141
|
+
its code. `requires_gpu` is the manifest's **only placement knob**: `true` routes the job
|
|
142
|
+
through the shared GPU queue (one GPU job at a time, across every plugin); `false` jobs run
|
|
143
|
+
on the CPU queue. Both are host-owned; the plugin never picks a queue or names a lane.
|
|
158
144
|
|
|
159
145
|
### 3. Implement the plugin object
|
|
160
146
|
|
|
@@ -289,13 +275,12 @@ The UI fragment is a self-contained `<style>` + `<div>` + `<script>` block. It h
|
|
|
289
275
|
|
|
290
276
|
There is **nothing to register**. On startup, the host scans the plugin directories
|
|
291
277
|
for manifests (no imports), builds a card from each, and gates compatibility against the
|
|
292
|
-
service version. When a
|
|
293
|
-
the manifest's `runtime.entrypoint` and instantiates the class
|
|
294
|
-
|
|
278
|
+
service version. When a plugin is actually needed, its **worker** imports the module named
|
|
279
|
+
in the manifest's `runtime.entrypoint` and instantiates the class inside the plugin's own
|
|
280
|
+
venv — the host never imports plugin code.
|
|
295
281
|
|
|
296
|
-
Because metadata is read
|
|
297
|
-
**lists** (greyed-out with a reason) instead of vanishing
|
|
298
|
-
imported until it's used.
|
|
282
|
+
Because metadata is read without any import, a plugin whose environment is broken (or whose
|
|
283
|
+
manifest is invalid) still **lists** (greyed-out with a reason) instead of vanishing.
|
|
299
284
|
|
|
300
285
|
That's it. Drop the directory in place with a `plugin.toml` and it will be discovered on
|
|
301
286
|
startup.
|
|
@@ -340,9 +325,8 @@ Browser (3LC Hub frontend, vanilla JS) Compute service (:5020)
|
|
|
340
325
|
└─ PLUGIN_API.authFetch(.../{subpath}) ───────▶ ANY /api/plugins/{id}/{subpath} → route handler
|
|
341
326
|
```
|
|
342
327
|
|
|
343
|
-
A plugin fragment is plain HTML+JS+CSS
|
|
344
|
-
|
|
345
|
-
can't tell. `PLUGIN_API` is the **single** host→fragment JS contract; a fragment should
|
|
328
|
+
A plugin fragment is plain HTML+JS+CSS, served by the plugin's worker and reverse-proxied
|
|
329
|
+
by the host — the frontend can't tell where it came from. `PLUGIN_API` is the **single** host→fragment JS contract; a fragment should
|
|
346
330
|
reach for nothing else (the `API` shorthand some plugins use is just
|
|
347
331
|
`var API = window.PLUGIN_API`).
|
|
348
332
|
|
|
@@ -440,9 +424,8 @@ socket.on('progress', function(data) { ... });
|
|
|
440
424
|
For plugins that need more than the generic `compute()` method (e.g., POST bodies, multiple
|
|
441
425
|
endpoints, streaming), return **relative Litestar route handlers** from `get_route_handlers()` —
|
|
442
426
|
bare `@get`/`@post` handlers with **relative** paths, no `Controller` and no `/api/plugins`
|
|
443
|
-
prefix. The host serves them through the plugin's own
|
|
444
|
-
`/api/plugins/{id}/{subpath}` catch-all
|
|
445
|
-
worker for `venv` plugins.
|
|
427
|
+
prefix. The host serves them through the plugin's own app in its worker, behind the generic
|
|
428
|
+
`/api/plugins/{id}/{subpath}` catch-all.
|
|
446
429
|
|
|
447
430
|
```python
|
|
448
431
|
from typing import Any
|
|
@@ -479,8 +462,8 @@ real example.
|
|
|
479
462
|
A plugin with a long-running task (training, inference, import) **declares** the job
|
|
480
463
|
in its manifest and **implements** it as `run_job(ctx)`. It does **not** grab a queue,
|
|
481
464
|
push a closure, or poll a shared `cancel_flag` — the host owns the queue, the GPU/CPU
|
|
482
|
-
slot lease, progress fan-out, listing, and cancellation.
|
|
483
|
-
|
|
465
|
+
slot lease, progress fan-out, listing, and cancellation. `run_job` runs in the plugin's
|
|
466
|
+
worker and only ever touches `ctx`.
|
|
484
467
|
|
|
485
468
|
**Declare the job in the manifest.** `requires_gpu` is the only knob:
|
|
486
469
|
|
|
@@ -582,8 +565,8 @@ independently.
|
|
|
582
565
|
**Custom events** — `ctx.emit(name, payload)` is reserved for telemetry the generic schema
|
|
583
566
|
**can't** express (e.g. a training plugin's per-epoch loss curve). The host relays it
|
|
584
567
|
verbatim on the plugin's namespace; the generic panel ignores it. The name `job_update` is
|
|
585
|
-
reserved and rejected. A plugin should **not** open its own SocketIO connection —
|
|
586
|
-
|
|
568
|
+
reserved and rejected. A plugin should **not** open its own SocketIO connection — the host
|
|
569
|
+
owns the transport; a plugin only ever emits through `ctx`.
|
|
587
570
|
|
|
588
571
|
```python
|
|
589
572
|
# backend — inside run_job, for a plugin-specific chart the generic panel can't show:
|
|
@@ -639,19 +622,19 @@ color: var(--accent); /* Accent color (#2a4a61) */
|
|
|
639
622
|
|
|
640
623
|
## Existing Plugins Reference
|
|
641
624
|
|
|
642
|
-
| Plugin ID | display_mode | Section |
|
|
625
|
+
| Plugin ID | display_mode | Section | GPU | Description |
|
|
643
626
|
|---|---|---|---|---|
|
|
644
|
-
| `importer` | sidebar | Data Ops |
|
|
645
|
-
| `exporter` | sidebar | Data Ops |
|
|
646
|
-
| `splitter` | sidebar | Data Ops |
|
|
647
|
-
| `merger` | sidebar | Data Ops |
|
|
648
|
-
| `image-metrics` | sidebar | Data Ops |
|
|
649
|
-
| `yolo` | sidebar | AI Tools |
|
|
650
|
-
| `sam3` | sidebar | AI Tools |
|
|
651
|
-
| `timm` | sidebar | AI Tools |
|
|
652
|
-
| `table-statistics` | hidden | Analysis |
|
|
653
|
-
| `run-insights` | action | Analysis |
|
|
654
|
-
| `table-insights` | action | Analysis |
|
|
627
|
+
| `importer` | sidebar | Data Ops | — | Import data (YOLO, COCO, Folder, CSV, Unlabeled) |
|
|
628
|
+
| `exporter` | sidebar | Data Ops | — | Export tables to CSV, XLSX, YOLO, COCO |
|
|
629
|
+
| `splitter` | sidebar | Data Ops | — | Split tables into train/val/test sets |
|
|
630
|
+
| `merger` | sidebar | Data Ops | — | Merge 2 tables by column join |
|
|
631
|
+
| `image-metrics` | sidebar | Data Ops | GPU | Image quality metrics (brightness, sharpness, noise, etc.) |
|
|
632
|
+
| `yolo` | sidebar | AI Tools | GPU | Ultralytics YOLO training + metrics collection |
|
|
633
|
+
| `sam3` | sidebar | AI Tools | GPU | Auto-labeling with SAM3/GroundingDINO |
|
|
634
|
+
| `timm` | sidebar | AI Tools | GPU | Image classification with timm models |
|
|
635
|
+
| `table-statistics` | hidden | Analysis | — | Per-column stats & image thumbnails (API-only) |
|
|
636
|
+
| `run-insights` | action | Analysis | — | Run statistics, health scores, per-class metrics |
|
|
637
|
+
| `table-insights` | action | Analysis | — | GT-only data quality analysis (bbox sizes, balance, etc.) |
|
|
655
638
|
|
|
656
639
|
---
|
|
657
640
|
|
|
@@ -742,30 +725,32 @@ Every sidebar plugin UI should follow this structure:
|
|
|
742
725
|
|
|
743
726
|
---
|
|
744
727
|
|
|
745
|
-
##
|
|
728
|
+
## The Dev Loop (Development)
|
|
729
|
+
|
|
730
|
+
The fast edit-run cycle is a **folder Source + an editable venv + a worker restart** — no
|
|
731
|
+
service restart, no rebuild:
|
|
746
732
|
|
|
747
|
-
|
|
733
|
+
1. Register your checkout as a folder Source (point `--plugin-dir` / the Settings page's
|
|
734
|
+
plugin-directories UI at the directory holding your plugin folder). The host provisions
|
|
735
|
+
the plugin's venv with `uv sync`, which installs your project **editable** — so the venv
|
|
736
|
+
always runs the code on disk.
|
|
737
|
+
2. Edit your plugin files.
|
|
738
|
+
3. Retire the worker; the next request cold-starts on the current code (sub-second):
|
|
748
739
|
|
|
749
740
|
```bash
|
|
750
|
-
|
|
751
|
-
# 2. Call the admin reload endpoint:
|
|
752
|
-
curl -X POST http://localhost:5020/api/admin/plugins/my-plugin/reload
|
|
741
|
+
curl -X POST http://localhost:5020/api/admin/plugins/my-plugin/worker/stop
|
|
753
742
|
```
|
|
754
743
|
|
|
755
744
|
Or from the browser console:
|
|
756
745
|
```javascript
|
|
757
|
-
TlcApi.authFetch(TlcApi.computeServiceUrl + '/api/admin/plugins/my-plugin/
|
|
746
|
+
TlcApi.authFetch(TlcApi.computeServiceUrl + '/api/admin/plugins/my-plugin/worker/stop', {method:'POST'})
|
|
758
747
|
.then(r => r.json()).then(console.log)
|
|
759
748
|
```
|
|
760
749
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
To unload a plugin entirely:
|
|
766
|
-
```bash
|
|
767
|
-
curl -X POST http://localhost:5020/api/admin/plugins/my-plugin/unload
|
|
768
|
-
```
|
|
750
|
+
For **dependency** changes (a new package, a version bump in your `pyproject.toml`), rebuild
|
|
751
|
+
the venv instead — `POST /api/admin/plugins/my-plugin/reload` runs `uv sync --reinstall` in
|
|
752
|
+
the background and retires the worker when the rebuilt venv swaps in. Running jobs in other
|
|
753
|
+
plugins are unaffected either way.
|
|
769
754
|
|
|
770
755
|
---
|
|
771
756
|
|
|
@@ -7,8 +7,8 @@ name = "3lc-compute-plugin-sdk"
|
|
|
7
7
|
# The plugin-contract (ABI) version. This IS tlc_plugin_sdk.SDK_CONTRACT_VERSION
|
|
8
8
|
# (read back via importlib.metadata) — one source of truth. SemVer MAJOR.MINOR.PATCH;
|
|
9
9
|
# the 0.x line is additive-only (see README → Status).
|
|
10
|
-
version = "0.2.
|
|
11
|
-
description = "Public Python SDK for building 3LC compute-service plugins
|
|
10
|
+
version = "0.2.3"
|
|
11
|
+
description = "Public Python SDK for building 3LC compute-service plugins."
|
|
12
12
|
requires-python = ">=3.10"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
authors = [{ name = "3LC", email = "support@3lc.ai" }]
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/asgi_app.py
RENAMED
|
@@ -4,23 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
This is the single route-authoring pattern: a plugin exposes its custom routes as
|
|
6
6
|
relative Litestar route handlers via :meth:`ComputePlugin.get_route_handlers`, and
|
|
7
|
-
the
|
|
7
|
+
the worker (``tlc_plugin_sdk.worker``) serves the app with uvicorn on a Unix socket
|
|
8
|
+
(or TCP, for a remote worker); the host reverse-proxies to it.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Because both modes serve the identical app, a plugin's routes get a real router,
|
|
15
|
-
request validation, multipart, and binary/streaming responses in **either** mode,
|
|
16
|
-
with no host/venv divergence. Litestar runs ``def`` handlers in a threadpool, so a
|
|
17
|
-
synchronous, CPU-bound custom route (e.g. preview inference) does not block the
|
|
18
|
-
event loop.
|
|
10
|
+
Because the worker runs a real Litestar app, a plugin's routes get a real router,
|
|
11
|
+
request validation, multipart, and binary/streaming responses. Litestar runs
|
|
12
|
+
``def`` handlers in a threadpool, so a synchronous, CPU-bound custom route (e.g.
|
|
13
|
+
preview inference) does not block the event loop.
|
|
19
14
|
|
|
20
15
|
The app also mounts the host-reserved generic routes (``/health``, ``/ui``,
|
|
21
|
-
``/compute``) so the worker can answer them over the socket
|
|
22
|
-
app these are harmless (the host serves ``/ui``/``/compute`` from its own reserved
|
|
23
|
-
param routes and never forwards them here).
|
|
16
|
+
``/compute``) so the worker can answer them over the socket.
|
|
24
17
|
|
|
25
18
|
Litestar is a base dependency of this SDK, but it is imported **here**, not in
|
|
26
19
|
the import-light :mod:`tlc_plugin_sdk` package surface — so
|
|
@@ -80,13 +73,12 @@ def build_plugin_app(
|
|
|
80
73
|
extra_handlers: list[BaseRouteHandler] | None = None,
|
|
81
74
|
debug: bool = False,
|
|
82
75
|
) -> Litestar:
|
|
83
|
-
"""Build the Litestar app serving ``plugin``'s HTTP surface
|
|
76
|
+
"""Build the Litestar app serving ``plugin``'s HTTP surface.
|
|
84
77
|
|
|
85
78
|
Args:
|
|
86
79
|
plugin: The plugin instance whose behavior the routes invoke.
|
|
87
|
-
extra_handlers:
|
|
88
|
-
``/jobs/{id}/cancel``, and ``/reclaim``)
|
|
89
|
-
app, whose job lifecycle is owned by the host ``JobManager``.
|
|
80
|
+
extra_handlers: The worker's job-channel handlers (the ``/jobs/{id}/run``
|
|
81
|
+
stream, ``/jobs/{id}/cancel``, and ``/reclaim``).
|
|
90
82
|
debug: Litestar debug flag.
|
|
91
83
|
|
|
92
84
|
Returns:
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/contract.py
RENAMED
|
@@ -77,7 +77,7 @@ class ComputePlugin(ABC):
|
|
|
77
77
|
"""Run a long-running job against a host-provided context.
|
|
78
78
|
|
|
79
79
|
The plugin reports progress/metrics and polls cancellation via ``ctx``;
|
|
80
|
-
the
|
|
80
|
+
the code runs in the plugin's worker and only ever touches ``ctx``.
|
|
81
81
|
|
|
82
82
|
Raises:
|
|
83
83
|
NotImplementedError: The default — a plugin that streams jobs must
|
|
@@ -98,8 +98,7 @@ class ComputePlugin(ABC):
|
|
|
98
98
|
Each handler's path is **relative** to the plugin's mount point
|
|
99
99
|
``/api/plugins/{plugin_id}/`` (e.g. a ``@get("/models")`` handler serves
|
|
100
100
|
``GET /api/plugins/{plugin_id}/models``). The handlers are served by the
|
|
101
|
-
plugin's own Litestar app
|
|
102
|
-
reverse-proxied to the worker for venv plugins (see
|
|
101
|
+
plugin's own Litestar app in its worker, reverse-proxied by the host (see
|
|
103
102
|
``tlc_plugin_sdk/asgi_app.py``); Litestar runs ``def`` handlers in a threadpool,
|
|
104
103
|
so a synchronous, blocking custom route does not block the event loop. The
|
|
105
104
|
reserved routes (``/run``, ``/health``, ``/ui``, ``/compute``, ``/jobs/*``)
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/job_context.py
RENAMED
|
@@ -3,15 +3,11 @@
|
|
|
3
3
|
"""``JobContext`` — the surface a plugin's ``run_job`` programs against.
|
|
4
4
|
|
|
5
5
|
A plugin implements ``run_job(ctx)`` and only ever touches ``ctx`` — it never
|
|
6
|
-
grabs a host queue or polls a shared ``cancel_flag``. The
|
|
7
|
-
|
|
8
|
-
the
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
streamed control-channel response, and a ``threading.Event`` set by the worker's
|
|
12
|
-
``/cancel`` endpoint.
|
|
13
|
-
- ``host`` mode: the host gives a sink that relays straight to SocketIO and a
|
|
14
|
-
cancel event tied to the host's job manager.
|
|
6
|
+
grabs a host queue or polls a shared ``cancel_flag``. The **sink** (where emitted
|
|
7
|
+
events go) and the **cancel signal** are injected: the worker harness gives a sink
|
|
8
|
+
that enqueues events for the streamed control-channel response, and a
|
|
9
|
+
``threading.Event`` set by the worker's ``/cancel`` endpoint. Tests inject their
|
|
10
|
+
own sink and event and drive ``run_job`` directly.
|
|
15
11
|
|
|
16
12
|
Import-light: stdlib only. Must not pull in the server stack.
|
|
17
13
|
"""
|
|
@@ -93,8 +89,7 @@ class JobContext:
|
|
|
93
89
|
generic Queue & Progress panel ignores it. Use :meth:`progress` /
|
|
94
90
|
:meth:`metric` / :meth:`log` for the generic panel, and this for
|
|
95
91
|
plugin-specific UI (e.g. a training plugin's per-epoch loss curve) — so a
|
|
96
|
-
plugin never opens its own SocketIO connection
|
|
97
|
-
portable (same ``run_job`` in either mode).
|
|
92
|
+
plugin never opens its own SocketIO connection; the host owns the transport.
|
|
98
93
|
|
|
99
94
|
Args:
|
|
100
95
|
name: Event name the plugin's UI listens for.
|
|
@@ -10,10 +10,10 @@ The bind transport is selectable: ``--socket`` (Unix domain socket, the default
|
|
|
10
10
|
supervisor uses) or ``--host``/``--port`` (TCP, e.g. ``--host 127.0.0.1 --port 9100``)
|
|
11
11
|
for a worker reachable over the network. Exactly one of the two must be given.
|
|
12
12
|
|
|
13
|
-
The worker serves the
|
|
14
|
-
|
|
13
|
+
The worker serves the plugin's Litestar app
|
|
14
|
+
(``tlc_plugin_sdk.asgi_app.build_plugin_app``): the plugin's own route handlers
|
|
15
15
|
plus the generic reserved routes (``/health``, ``/ui``, ``/compute``). On top of that
|
|
16
|
-
it adds the
|
|
16
|
+
it adds the job channel the host supervisor drives:
|
|
17
17
|
|
|
18
18
|
- ``POST /jobs/{job_id}/run`` → runs ``run_job(ctx)`` on a thread; the response
|
|
19
19
|
**streams NDJSON events** (progress/metric/log)
|
|
@@ -28,8 +28,8 @@ process cannot know that another plugin's worker needs the card. The host decide
|
|
|
28
28
|
when; the worker is the only side that can act, because a CUDA allocator is
|
|
29
29
|
per-process and the supervisor's only in-process lever is killing the worker.
|
|
30
30
|
|
|
31
|
-
Because the worker runs a real Litestar app, a plugin's custom routes get
|
|
32
|
-
router, validation, multipart, and binary/streaming behavior
|
|
31
|
+
Because the worker runs a real Litestar app, a plugin's custom routes get a real
|
|
32
|
+
router, validation, multipart, and binary/streaming behavior —
|
|
33
33
|
and Litestar runs synchronous ``def`` handlers in a threadpool, so CPU-bound routes
|
|
34
34
|
don't block the worker's event loop. Litestar + uvicorn are base dependencies of
|
|
35
35
|
this SDK; they are imported here, not by the import-light :mod:`tlc_plugin_sdk`
|
|
@@ -26,36 +26,36 @@ name = "3lc"
|
|
|
26
26
|
version = "3.2.1"
|
|
27
27
|
source = { registry = "https://pypi.org/simple" }
|
|
28
28
|
dependencies = [
|
|
29
|
-
{ name = "anyio"
|
|
30
|
-
{ name = "cachetools"
|
|
31
|
-
{ name = "click"
|
|
32
|
-
{ name = "cryptlex-lexactivator"
|
|
33
|
-
{ name = "filelock"
|
|
34
|
-
{ name = "litestar"
|
|
35
|
-
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "
|
|
36
|
-
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "
|
|
37
|
-
{ name = "opencv-python"
|
|
38
|
-
{ name = "packaging"
|
|
39
|
-
{ name = "pillow"
|
|
40
|
-
{ name = "platformdirs"
|
|
41
|
-
{ name = "pyarrow"
|
|
42
|
-
{ name = "pycocotools"
|
|
43
|
-
{ name = "pydantic"
|
|
44
|
-
{ name = "pyperclip"
|
|
45
|
-
{ name = "python-dateutil"
|
|
29
|
+
{ name = "anyio" },
|
|
30
|
+
{ name = "cachetools" },
|
|
31
|
+
{ name = "click" },
|
|
32
|
+
{ name = "cryptlex-lexactivator" },
|
|
33
|
+
{ name = "filelock" },
|
|
34
|
+
{ name = "litestar" },
|
|
35
|
+
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
|
36
|
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
37
|
+
{ name = "opencv-python" },
|
|
38
|
+
{ name = "packaging" },
|
|
39
|
+
{ name = "pillow" },
|
|
40
|
+
{ name = "platformdirs" },
|
|
41
|
+
{ name = "pyarrow" },
|
|
42
|
+
{ name = "pycocotools" },
|
|
43
|
+
{ name = "pydantic" },
|
|
44
|
+
{ name = "pyperclip" },
|
|
45
|
+
{ name = "python-dateutil" },
|
|
46
46
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
|
47
|
-
{ name = "pyyaml"
|
|
48
|
-
{ name = "randomname"
|
|
49
|
-
{ name = "rich"
|
|
50
|
-
{ name = "ruamel-yaml"
|
|
51
|
-
{ name = "sentry-sdk", extra = ["litestar"]
|
|
52
|
-
{ name = "termcolor"
|
|
53
|
-
{ name = "textual"
|
|
54
|
-
{ name = "tomli"
|
|
55
|
-
{ name = "tqdm"
|
|
56
|
-
{ name = "typing-extensions"
|
|
57
|
-
{ name = "uvicorn"
|
|
58
|
-
{ name = "watchdog"
|
|
47
|
+
{ name = "pyyaml" },
|
|
48
|
+
{ name = "randomname" },
|
|
49
|
+
{ name = "rich" },
|
|
50
|
+
{ name = "ruamel-yaml" },
|
|
51
|
+
{ name = "sentry-sdk", extra = ["litestar"] },
|
|
52
|
+
{ name = "termcolor" },
|
|
53
|
+
{ name = "textual" },
|
|
54
|
+
{ name = "tomli" },
|
|
55
|
+
{ name = "tqdm" },
|
|
56
|
+
{ name = "typing-extensions" },
|
|
57
|
+
{ name = "uvicorn" },
|
|
58
|
+
{ name = "watchdog" },
|
|
59
59
|
]
|
|
60
60
|
wheels = [
|
|
61
61
|
{ url = "https://files.pythonhosted.org/packages/8f/1b/79914d46251a34c898d7f0c31e0f3f8e3d1b05889d43418e84cca2296254/3lc-3.2.1-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:454d087f5ee6f2118f026bd2de8748225b71274dc43f394c0aa60aa0477d332b", size = 10291323, upload-time = "2026-08-14T18:20:27.851Z" },
|
|
@@ -78,29 +78,29 @@ wheels = [
|
|
|
78
78
|
|
|
79
79
|
[package.optional-dependencies]
|
|
80
80
|
pandas = [
|
|
81
|
-
{ name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "
|
|
82
|
-
{ name = "pandas", version = "3.0.3", source = { registry = "https://pypi.org/simple" }, marker = "
|
|
81
|
+
{ name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
|
82
|
+
{ name = "pandas", version = "3.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
83
83
|
]
|
|
84
84
|
|
|
85
85
|
[[package]]
|
|
86
86
|
name = "3lc-compute-plugin-sdk"
|
|
87
|
-
version = "0.2.
|
|
87
|
+
version = "0.2.3"
|
|
88
88
|
source = { editable = "." }
|
|
89
89
|
dependencies = [
|
|
90
|
-
{ name = "litestar"
|
|
91
|
-
{ name = "uvicorn"
|
|
90
|
+
{ name = "litestar" },
|
|
91
|
+
{ name = "uvicorn" },
|
|
92
92
|
]
|
|
93
93
|
|
|
94
94
|
[package.optional-dependencies]
|
|
95
95
|
shared = [
|
|
96
|
-
{ name = "3lc", extra = ["pandas"]
|
|
96
|
+
{ name = "3lc", extra = ["pandas"] },
|
|
97
97
|
]
|
|
98
98
|
|
|
99
99
|
[package.dev-dependencies]
|
|
100
100
|
dev = [
|
|
101
|
-
{ name = "mypy"
|
|
102
|
-
{ name = "pytest"
|
|
103
|
-
{ name = "ruff"
|
|
101
|
+
{ name = "mypy" },
|
|
102
|
+
{ name = "pytest" },
|
|
103
|
+
{ name = "ruff" },
|
|
104
104
|
]
|
|
105
105
|
|
|
106
106
|
[package.metadata]
|
|
@@ -132,9 +132,9 @@ name = "anyio"
|
|
|
132
132
|
version = "4.14.0"
|
|
133
133
|
source = { registry = "https://pypi.org/simple" }
|
|
134
134
|
dependencies = [
|
|
135
|
-
{ name = "exceptiongroup", marker = "
|
|
136
|
-
{ name = "idna"
|
|
137
|
-
{ name = "typing-extensions", marker = "
|
|
135
|
+
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
|
136
|
+
{ name = "idna" },
|
|
137
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
138
138
|
]
|
|
139
139
|
sdist = { url = "https://files.pythonhosted.org/packages/1c/b5/001890774a9552aff22502b8da382593109ce0c95314abaebbb116567545/anyio-4.14.0.tar.gz", hash = "sha256:b47c1f9ccf73e67021df785332508f99379c68fa7d0684e8e3492cb1d4b23f89", size = 253586, upload-time = "2026-06-15T22:00:49.021Z" }
|
|
140
140
|
wheels = [
|
|
@@ -234,7 +234,7 @@ name = "exceptiongroup"
|
|
|
234
234
|
version = "1.3.1"
|
|
235
235
|
source = { registry = "https://pypi.org/simple" }
|
|
236
236
|
dependencies = [
|
|
237
|
-
{ name = "typing-extensions"
|
|
237
|
+
{ name = "typing-extensions" },
|
|
238
238
|
]
|
|
239
239
|
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
|
240
240
|
wheels = [
|
|
@@ -267,7 +267,7 @@ name = "fire"
|
|
|
267
267
|
version = "0.7.1"
|
|
268
268
|
source = { registry = "https://pypi.org/simple" }
|
|
269
269
|
dependencies = [
|
|
270
|
-
{ name = "termcolor"
|
|
270
|
+
{ name = "termcolor" },
|
|
271
271
|
]
|
|
272
272
|
sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720, upload-time = "2025-08-16T20:20:24.175Z" }
|
|
273
273
|
wheels = [
|
|
@@ -288,8 +288,8 @@ name = "httpcore"
|
|
|
288
288
|
version = "1.0.9"
|
|
289
289
|
source = { registry = "https://pypi.org/simple" }
|
|
290
290
|
dependencies = [
|
|
291
|
-
{ name = "certifi"
|
|
292
|
-
{ name = "h11"
|
|
291
|
+
{ name = "certifi" },
|
|
292
|
+
{ name = "h11" },
|
|
293
293
|
]
|
|
294
294
|
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" }
|
|
295
295
|
wheels = [
|
|
@@ -301,10 +301,10 @@ name = "httpx"
|
|
|
301
301
|
version = "0.28.1"
|
|
302
302
|
source = { registry = "https://pypi.org/simple" }
|
|
303
303
|
dependencies = [
|
|
304
|
-
{ name = "anyio"
|
|
305
|
-
{ name = "certifi"
|
|
306
|
-
{ name = "httpcore"
|
|
307
|
-
{ name = "idna"
|
|
304
|
+
{ name = "anyio" },
|
|
305
|
+
{ name = "certifi" },
|
|
306
|
+
{ name = "httpcore" },
|
|
307
|
+
{ name = "idna" },
|
|
308
308
|
]
|
|
309
309
|
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" }
|
|
310
310
|
wheels = [
|
|
@@ -419,7 +419,7 @@ name = "linkify-it-py"
|
|
|
419
419
|
version = "2.1.0"
|
|
420
420
|
source = { registry = "https://pypi.org/simple" }
|
|
421
421
|
dependencies = [
|
|
422
|
-
{ name = "uc-micro-py"
|
|
422
|
+
{ name = "uc-micro-py" },
|
|
423
423
|
]
|
|
424
424
|
sdist = { url = "https://files.pythonhosted.org/packages/2e/c9/06ea13676ef354f0af6169587ae292d3e2406e212876a413bf9eece4eb23/linkify_it_py-2.1.0.tar.gz", hash = "sha256:43360231720999c10e9328dc3691160e27a718e280673d444c38d7d3aaa3b98b", size = 29158, upload-time = "2026-03-01T07:48:47.683Z" }
|
|
425
425
|
wheels = [
|
|
@@ -431,20 +431,20 @@ name = "litestar"
|
|
|
431
431
|
version = "2.24.0"
|
|
432
432
|
source = { registry = "https://pypi.org/simple" }
|
|
433
433
|
dependencies = [
|
|
434
|
-
{ name = "anyio"
|
|
435
|
-
{ name = "click"
|
|
436
|
-
{ name = "exceptiongroup", marker = "
|
|
437
|
-
{ name = "httpx"
|
|
438
|
-
{ name = "litestar-htmx"
|
|
439
|
-
{ name = "msgspec"
|
|
440
|
-
{ name = "multidict"
|
|
441
|
-
{ name = "multipart"
|
|
442
|
-
{ name = "polyfactory"
|
|
443
|
-
{ name = "pyyaml"
|
|
444
|
-
{ name = "rich"
|
|
445
|
-
{ name = "rich-click"
|
|
446
|
-
{ name = "sniffio"
|
|
447
|
-
{ name = "typing-extensions"
|
|
434
|
+
{ name = "anyio" },
|
|
435
|
+
{ name = "click" },
|
|
436
|
+
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
|
437
|
+
{ name = "httpx" },
|
|
438
|
+
{ name = "litestar-htmx" },
|
|
439
|
+
{ name = "msgspec" },
|
|
440
|
+
{ name = "multidict" },
|
|
441
|
+
{ name = "multipart" },
|
|
442
|
+
{ name = "polyfactory" },
|
|
443
|
+
{ name = "pyyaml" },
|
|
444
|
+
{ name = "rich" },
|
|
445
|
+
{ name = "rich-click" },
|
|
446
|
+
{ name = "sniffio" },
|
|
447
|
+
{ name = "typing-extensions" },
|
|
448
448
|
]
|
|
449
449
|
sdist = { url = "https://files.pythonhosted.org/packages/42/f6/33619a1562c6732dab211a967b1e7af3285de29d655c0b37b3f379aa2700/litestar-2.24.0.tar.gz", hash = "sha256:8f4b137cb115554b9fbc12bd01d398d5bb40ba85f2d333dd73f4b747308bbb46", size = 383070, upload-time = "2026-06-11T11:27:00.519Z" }
|
|
450
450
|
wheels = [
|
|
@@ -465,7 +465,7 @@ name = "markdown-it-py"
|
|
|
465
465
|
version = "4.2.0"
|
|
466
466
|
source = { registry = "https://pypi.org/simple" }
|
|
467
467
|
dependencies = [
|
|
468
|
-
{ name = "mdurl"
|
|
468
|
+
{ name = "mdurl" },
|
|
469
469
|
]
|
|
470
470
|
sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" }
|
|
471
471
|
wheels = [
|
|
@@ -474,10 +474,10 @@ wheels = [
|
|
|
474
474
|
|
|
475
475
|
[package.optional-dependencies]
|
|
476
476
|
linkify = [
|
|
477
|
-
{ name = "linkify-it-py"
|
|
477
|
+
{ name = "linkify-it-py" },
|
|
478
478
|
]
|
|
479
479
|
plugins = [
|
|
480
|
-
{ name = "mdit-py-plugins"
|
|
480
|
+
{ name = "mdit-py-plugins" },
|
|
481
481
|
]
|
|
482
482
|
|
|
483
483
|
[[package]]
|
|
@@ -485,7 +485,7 @@ name = "mdit-py-plugins"
|
|
|
485
485
|
version = "0.6.1"
|
|
486
486
|
source = { registry = "https://pypi.org/simple" }
|
|
487
487
|
dependencies = [
|
|
488
|
-
{ name = "markdown-it-py"
|
|
488
|
+
{ name = "markdown-it-py" },
|
|
489
489
|
]
|
|
490
490
|
sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" }
|
|
491
491
|
wheels = [
|
|
@@ -562,7 +562,7 @@ name = "multidict"
|
|
|
562
562
|
version = "6.7.1"
|
|
563
563
|
source = { registry = "https://pypi.org/simple" }
|
|
564
564
|
dependencies = [
|
|
565
|
-
{ name = "typing-extensions", marker = "
|
|
565
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
|
566
566
|
]
|
|
567
567
|
sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" }
|
|
568
568
|
wheels = [
|
|
@@ -709,12 +709,12 @@ name = "mypy"
|
|
|
709
709
|
version = "2.1.0"
|
|
710
710
|
source = { registry = "https://pypi.org/simple" }
|
|
711
711
|
dependencies = [
|
|
712
|
-
{ name = "ast-serialize"
|
|
713
|
-
{ name = "librt", marker = "
|
|
714
|
-
{ name = "mypy-extensions"
|
|
715
|
-
{ name = "pathspec"
|
|
716
|
-
{ name = "tomli", marker = "
|
|
717
|
-
{ name = "typing-extensions"
|
|
712
|
+
{ name = "ast-serialize" },
|
|
713
|
+
{ name = "librt", marker = "platform_python_implementation != 'PyPy'" },
|
|
714
|
+
{ name = "mypy-extensions" },
|
|
715
|
+
{ name = "pathspec" },
|
|
716
|
+
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
|
717
|
+
{ name = "typing-extensions" },
|
|
718
718
|
]
|
|
719
719
|
sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" }
|
|
720
720
|
wheels = [
|
|
@@ -934,8 +934,8 @@ name = "opencv-python"
|
|
|
934
934
|
version = "4.13.0.92"
|
|
935
935
|
source = { registry = "https://pypi.org/simple" }
|
|
936
936
|
dependencies = [
|
|
937
|
-
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "
|
|
938
|
-
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "
|
|
937
|
+
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
|
938
|
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
939
939
|
]
|
|
940
940
|
wheels = [
|
|
941
941
|
{ url = "https://files.pythonhosted.org/packages/fc/6f/5a28fef4c4a382be06afe3938c64cc168223016fa520c5abaf37e8862aa5/opencv_python-4.13.0.92-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:caf60c071ec391ba51ed00a4a920f996d0b64e3e46068aac1f646b5de0326a19", size = 46247052, upload-time = "2026-02-05T07:01:25.046Z" },
|
|
@@ -967,10 +967,10 @@ resolution-markers = [
|
|
|
967
967
|
"python_full_version < '3.11' and sys_platform == 'win32'",
|
|
968
968
|
]
|
|
969
969
|
dependencies = [
|
|
970
|
-
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }
|
|
971
|
-
{ name = "python-dateutil"
|
|
972
|
-
{ name = "pytz"
|
|
973
|
-
{ name = "tzdata"
|
|
970
|
+
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
|
|
971
|
+
{ name = "python-dateutil" },
|
|
972
|
+
{ name = "pytz" },
|
|
973
|
+
{ name = "tzdata" },
|
|
974
974
|
]
|
|
975
975
|
sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" }
|
|
976
976
|
wheels = [
|
|
@@ -1039,9 +1039,9 @@ resolution-markers = [
|
|
|
1039
1039
|
"python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform == 'win32'",
|
|
1040
1040
|
]
|
|
1041
1041
|
dependencies = [
|
|
1042
|
-
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }
|
|
1043
|
-
{ name = "python-dateutil"
|
|
1044
|
-
{ name = "tzdata", marker = "
|
|
1042
|
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" } },
|
|
1043
|
+
{ name = "python-dateutil" },
|
|
1044
|
+
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
|
1045
1045
|
]
|
|
1046
1046
|
sdist = { url = "https://files.pythonhosted.org/packages/f8/87/4341c6252d1c47b08768c3d25ac487362bf403f0313ddae4a2a26c9b1b4c/pandas-3.0.3.tar.gz", hash = "sha256:696a4a00a2a2a35d4e5deb3fc946641b96c944f02230e4f76137fe35d806c4fc", size = 4651414, upload-time = "2026-05-11T18:54:29.21Z" }
|
|
1047
1047
|
wheels = [
|
|
@@ -1224,8 +1224,8 @@ name = "polyfactory"
|
|
|
1224
1224
|
version = "3.3.0"
|
|
1225
1225
|
source = { registry = "https://pypi.org/simple" }
|
|
1226
1226
|
dependencies = [
|
|
1227
|
-
{ name = "faker"
|
|
1228
|
-
{ name = "typing-extensions"
|
|
1227
|
+
{ name = "faker" },
|
|
1228
|
+
{ name = "typing-extensions" },
|
|
1229
1229
|
]
|
|
1230
1230
|
sdist = { url = "https://files.pythonhosted.org/packages/85/68/7717bd9e63ed254617a7d3dc9260904fb736d6ea203e58ffddcb186c64e4/polyfactory-3.3.0.tar.gz", hash = "sha256:237258b6ff43edf362ffd1f68086bb796466f786adfa002b0ac256dbf2246e9a", size = 348668, upload-time = "2026-02-22T09:46:28.01Z" }
|
|
1231
1231
|
wheels = [
|
|
@@ -1294,8 +1294,8 @@ name = "pycocotools"
|
|
|
1294
1294
|
version = "2.0.11"
|
|
1295
1295
|
source = { registry = "https://pypi.org/simple" }
|
|
1296
1296
|
dependencies = [
|
|
1297
|
-
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "
|
|
1298
|
-
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "
|
|
1297
|
+
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
|
1298
|
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
1299
1299
|
]
|
|
1300
1300
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/df/32354b5dda963ffdfc8f75c9acf8828ef7890723a4ed57bb3ff2dc1d6f7e/pycocotools-2.0.11.tar.gz", hash = "sha256:34254d76da85576fcaf5c1f3aa9aae16b8cb15418334ba4283b800796bd1993d", size = 25381, upload-time = "2025-12-15T22:31:46.148Z" }
|
|
1301
1301
|
wheels = [
|
|
@@ -1341,10 +1341,10 @@ name = "pydantic"
|
|
|
1341
1341
|
version = "2.13.4"
|
|
1342
1342
|
source = { registry = "https://pypi.org/simple" }
|
|
1343
1343
|
dependencies = [
|
|
1344
|
-
{ name = "annotated-types"
|
|
1345
|
-
{ name = "pydantic-core"
|
|
1346
|
-
{ name = "typing-extensions"
|
|
1347
|
-
{ name = "typing-inspection"
|
|
1344
|
+
{ name = "annotated-types" },
|
|
1345
|
+
{ name = "pydantic-core" },
|
|
1346
|
+
{ name = "typing-extensions" },
|
|
1347
|
+
{ name = "typing-inspection" },
|
|
1348
1348
|
]
|
|
1349
1349
|
sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" }
|
|
1350
1350
|
wheels = [
|
|
@@ -1356,7 +1356,7 @@ name = "pydantic-core"
|
|
|
1356
1356
|
version = "2.46.4"
|
|
1357
1357
|
source = { registry = "https://pypi.org/simple" }
|
|
1358
1358
|
dependencies = [
|
|
1359
|
-
{ name = "typing-extensions"
|
|
1359
|
+
{ name = "typing-extensions" },
|
|
1360
1360
|
]
|
|
1361
1361
|
sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" }
|
|
1362
1362
|
wheels = [
|
|
@@ -1491,12 +1491,12 @@ version = "9.1.0"
|
|
|
1491
1491
|
source = { registry = "https://pypi.org/simple" }
|
|
1492
1492
|
dependencies = [
|
|
1493
1493
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
1494
|
-
{ name = "exceptiongroup", marker = "
|
|
1495
|
-
{ name = "iniconfig"
|
|
1496
|
-
{ name = "packaging"
|
|
1497
|
-
{ name = "pluggy"
|
|
1498
|
-
{ name = "pygments"
|
|
1499
|
-
{ name = "tomli", marker = "
|
|
1494
|
+
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
|
1495
|
+
{ name = "iniconfig" },
|
|
1496
|
+
{ name = "packaging" },
|
|
1497
|
+
{ name = "pluggy" },
|
|
1498
|
+
{ name = "pygments" },
|
|
1499
|
+
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
|
1500
1500
|
]
|
|
1501
1501
|
sdist = { url = "https://files.pythonhosted.org/packages/84/0e/b5858858d74958632c49b72cb25a3976ff9f632397626715be71c89d3971/pytest-9.1.0.tar.gz", hash = "sha256:41dd9148c08072446394cefd3d79701701335a9f4cae69ba92e39f6c7f5c061c", size = 1634181, upload-time = "2026-06-13T18:52:45.983Z" }
|
|
1502
1502
|
wheels = [
|
|
@@ -1508,7 +1508,7 @@ name = "python-dateutil"
|
|
|
1508
1508
|
version = "2.9.0.post0"
|
|
1509
1509
|
source = { registry = "https://pypi.org/simple" }
|
|
1510
1510
|
dependencies = [
|
|
1511
|
-
{ name = "six"
|
|
1511
|
+
{ name = "six" },
|
|
1512
1512
|
]
|
|
1513
1513
|
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" }
|
|
1514
1514
|
wheels = [
|
|
@@ -1612,7 +1612,7 @@ name = "randomname"
|
|
|
1612
1612
|
version = "0.2.1"
|
|
1613
1613
|
source = { registry = "https://pypi.org/simple" }
|
|
1614
1614
|
dependencies = [
|
|
1615
|
-
{ name = "fire"
|
|
1615
|
+
{ name = "fire" },
|
|
1616
1616
|
]
|
|
1617
1617
|
sdist = { url = "https://files.pythonhosted.org/packages/e8/c2/525e9e9b458c3ca493d9bd0871f3ed9b51446d26fe82d462494de188f848/randomname-0.2.1.tar.gz", hash = "sha256:b79b98302ba4479164b0a4f87995b7bebbd1d91012aeda483341e3e58ace520e", size = 64242, upload-time = "2023-01-29T02:42:26.469Z" }
|
|
1618
1618
|
|
|
@@ -1621,9 +1621,9 @@ name = "rich"
|
|
|
1621
1621
|
version = "13.9.4"
|
|
1622
1622
|
source = { registry = "https://pypi.org/simple" }
|
|
1623
1623
|
dependencies = [
|
|
1624
|
-
{ name = "markdown-it-py"
|
|
1625
|
-
{ name = "pygments"
|
|
1626
|
-
{ name = "typing-extensions", marker = "
|
|
1624
|
+
{ name = "markdown-it-py" },
|
|
1625
|
+
{ name = "pygments" },
|
|
1626
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
|
1627
1627
|
]
|
|
1628
1628
|
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149, upload-time = "2024-11-01T16:43:57.873Z" }
|
|
1629
1629
|
wheels = [
|
|
@@ -1635,10 +1635,10 @@ name = "rich-click"
|
|
|
1635
1635
|
version = "1.9.8"
|
|
1636
1636
|
source = { registry = "https://pypi.org/simple" }
|
|
1637
1637
|
dependencies = [
|
|
1638
|
-
{ name = "click"
|
|
1638
|
+
{ name = "click" },
|
|
1639
1639
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
1640
|
-
{ name = "rich"
|
|
1641
|
-
{ name = "typing-extensions", marker = "
|
|
1640
|
+
{ name = "rich" },
|
|
1641
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
|
1642
1642
|
]
|
|
1643
1643
|
sdist = { url = "https://files.pythonhosted.org/packages/f7/ea/21e4867ea0ef881ffd4c0550fc21a061435e50d6324bcd034396633cbc18/rich_click-1.9.8.tar.gz", hash = "sha256:4008f921da88b5d91646c134ec881c1500e5a6b3f093e90e8f29400e09608371", size = 75363, upload-time = "2026-05-28T19:54:59.144Z" }
|
|
1644
1644
|
wheels = [
|
|
@@ -1684,8 +1684,8 @@ name = "sentry-sdk"
|
|
|
1684
1684
|
version = "2.63.0"
|
|
1685
1685
|
source = { registry = "https://pypi.org/simple" }
|
|
1686
1686
|
dependencies = [
|
|
1687
|
-
{ name = "certifi"
|
|
1688
|
-
{ name = "urllib3"
|
|
1687
|
+
{ name = "certifi" },
|
|
1688
|
+
{ name = "urllib3" },
|
|
1689
1689
|
]
|
|
1690
1690
|
sdist = { url = "https://files.pythonhosted.org/packages/ba/c8/b3c970a5b186722d276cd40a05b3254e03bccc0208560aff20f612e018e8/sentry_sdk-2.63.0.tar.gz", hash = "sha256:2a1502bf864769275dbc8c2c9fc7a0f7f5e18358180b615d262d13a31ffba216", size = 912449, upload-time = "2026-06-16T12:45:57.553Z" }
|
|
1691
1691
|
wheels = [
|
|
@@ -1694,7 +1694,7 @@ wheels = [
|
|
|
1694
1694
|
|
|
1695
1695
|
[package.optional-dependencies]
|
|
1696
1696
|
litestar = [
|
|
1697
|
-
{ name = "litestar"
|
|
1697
|
+
{ name = "litestar" },
|
|
1698
1698
|
]
|
|
1699
1699
|
|
|
1700
1700
|
[[package]]
|
|
@@ -1729,10 +1729,10 @@ name = "textual"
|
|
|
1729
1729
|
version = "0.89.1"
|
|
1730
1730
|
source = { registry = "https://pypi.org/simple" }
|
|
1731
1731
|
dependencies = [
|
|
1732
|
-
{ name = "markdown-it-py", extra = ["linkify", "plugins"]
|
|
1733
|
-
{ name = "platformdirs"
|
|
1734
|
-
{ name = "rich"
|
|
1735
|
-
{ name = "typing-extensions"
|
|
1732
|
+
{ name = "markdown-it-py", extra = ["linkify", "plugins"] },
|
|
1733
|
+
{ name = "platformdirs" },
|
|
1734
|
+
{ name = "rich" },
|
|
1735
|
+
{ name = "typing-extensions" },
|
|
1736
1736
|
]
|
|
1737
1737
|
sdist = { url = "https://files.pythonhosted.org/packages/4b/cb/b3ff0e45d812997a527cb581a4cd602f0b28793450aa26201969fd6ce42c/textual-0.89.1.tar.gz", hash = "sha256:66befe80e2bca5a8c876cd8ceeaf01752267b6b1dc1d0f73071f1f1e15d90cc8", size = 1517074, upload-time = "2024-12-05T15:17:12.903Z" }
|
|
1738
1738
|
wheels = [
|
|
@@ -1819,7 +1819,7 @@ name = "typing-inspection"
|
|
|
1819
1819
|
version = "0.4.2"
|
|
1820
1820
|
source = { registry = "https://pypi.org/simple" }
|
|
1821
1821
|
dependencies = [
|
|
1822
|
-
{ name = "typing-extensions"
|
|
1822
|
+
{ name = "typing-extensions" },
|
|
1823
1823
|
]
|
|
1824
1824
|
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
|
|
1825
1825
|
wheels = [
|
|
@@ -1858,9 +1858,9 @@ name = "uvicorn"
|
|
|
1858
1858
|
version = "0.49.0"
|
|
1859
1859
|
source = { registry = "https://pypi.org/simple" }
|
|
1860
1860
|
dependencies = [
|
|
1861
|
-
{ name = "click"
|
|
1862
|
-
{ name = "h11"
|
|
1863
|
-
{ name = "typing-extensions", marker = "
|
|
1861
|
+
{ name = "click" },
|
|
1862
|
+
{ name = "h11" },
|
|
1863
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
|
1864
1864
|
]
|
|
1865
1865
|
sdist = { url = "https://files.pythonhosted.org/packages/c4/1f/fa18009dea8469069cca78a4e877a008ab78f08b064bfc9ab891579077ff/uvicorn-0.49.0.tar.gz", hash = "sha256:ebf4271aa580d9de97f93192d4595176df6e91f9aae919ca73e4fc07df1e66a3", size = 91284, upload-time = "2026-06-03T22:01:30.448Z" }
|
|
1866
1866
|
wheels = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/alias_ui.py
RENAMED
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/aliases.py
RENAMED
|
File without changes
|
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/config_ui.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/images.py
RENAMED
|
File without changes
|
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/labels.py
RENAMED
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/modality.py
RENAMED
|
File without changes
|
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/naming.py
RENAMED
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/ui_inject.py
RENAMED
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/src/tlc_plugin_sdk/shared/url_utils.py
RENAMED
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/tests/test_data_source_routes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{3lc_compute_plugin_sdk-0.2.2 → 3lc_compute_plugin_sdk-0.2.3}/tests/test_worker_gpu_reclaim.py
RENAMED
|
File without changes
|