unitlab 2.5.1__tar.gz → 3.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. unitlab-3.0.1/PKG-INFO +464 -0
  2. unitlab-3.0.1/README.md +431 -0
  3. {unitlab-2.5.1 → unitlab-3.0.1}/pyproject.toml +5 -3
  4. unitlab-3.0.1/src/unitlab/__init__.py +102 -0
  5. unitlab-3.0.1/src/unitlab/__main__.py +3 -0
  6. unitlab-3.0.1/src/unitlab/_downloader.py +106 -0
  7. unitlab-3.0.1/src/unitlab/_grouping.py +75 -0
  8. unitlab-3.0.1/src/unitlab/_http.py +160 -0
  9. unitlab-3.0.1/src/unitlab/_uploader.py +418 -0
  10. unitlab-3.0.1/src/unitlab/_waiter.py +80 -0
  11. unitlab-3.0.1/src/unitlab/cli.py +1393 -0
  12. unitlab-3.0.1/src/unitlab/client.py +91 -0
  13. {unitlab-2.5.1 → unitlab-3.0.1}/src/unitlab/exceptions.py +23 -14
  14. unitlab-3.0.1/src/unitlab/ontology.py +273 -0
  15. unitlab-3.0.1/src/unitlab/py.typed +0 -0
  16. unitlab-3.0.1/src/unitlab/resources/__init__.py +29 -0
  17. unitlab-3.0.1/src/unitlab/resources/_base.py +41 -0
  18. unitlab-3.0.1/src/unitlab/resources/assets.py +302 -0
  19. unitlab-3.0.1/src/unitlab/resources/cloud.py +84 -0
  20. unitlab-3.0.1/src/unitlab/resources/datasets.py +261 -0
  21. unitlab-3.0.1/src/unitlab/resources/embeddings.py +127 -0
  22. unitlab-3.0.1/src/unitlab/resources/ontologies.py +129 -0
  23. unitlab-3.0.1/src/unitlab/resources/projects.py +611 -0
  24. unitlab-3.0.1/src/unitlab/resources/releases.py +153 -0
  25. unitlab-3.0.1/src/unitlab/resources/workflow.py +349 -0
  26. unitlab-3.0.1/src/unitlab/types.py +153 -0
  27. unitlab-3.0.1/tests/test_cli.py +593 -0
  28. unitlab-3.0.1/tests/test_client.py +679 -0
  29. unitlab-3.0.1/tests/test_downloader.py +150 -0
  30. unitlab-3.0.1/tests/test_embeddings.py +373 -0
  31. unitlab-3.0.1/tests/test_http.py +73 -0
  32. unitlab-3.0.1/tests/test_uploader.py +545 -0
  33. unitlab-2.5.1/.claude/settings.local.json +0 -49
  34. unitlab-2.5.1/PKG-INFO +0 -213
  35. unitlab-2.5.1/README.md +0 -179
  36. unitlab-2.5.1/src/unitlab/__init__.py +0 -7
  37. unitlab-2.5.1/src/unitlab/__main__.py +0 -3
  38. unitlab-2.5.1/src/unitlab/cli.py +0 -127
  39. unitlab-2.5.1/src/unitlab/client.py +0 -561
  40. {unitlab-2.5.1 → unitlab-3.0.1}/.gitignore +0 -0
  41. {unitlab-2.5.1 → unitlab-3.0.1}/LICENSE.md +0 -0
  42. {unitlab-2.5.1 → unitlab-3.0.1}/src/unitlab/_config.py +0 -0
unitlab-3.0.1/PKG-INFO ADDED
@@ -0,0 +1,464 @@
1
+ Metadata-Version: 2.4
2
+ Name: unitlab
3
+ Version: 3.0.1
4
+ Summary: Python SDK for the Unitlab.ai data annotation platform
5
+ Project-URL: Homepage, https://unitlab.ai
6
+ Project-URL: Documentation, https://docs.unitlab.ai
7
+ Project-URL: Repository, https://github.com/teamunitlab/unitlab-sdk
8
+ Author-email: "Unitlab Inc." <team@unitlab.ai>
9
+ License-Expression: MIT
10
+ License-File: LICENSE.md
11
+ Keywords: annotation,data-labeling,machine-learning,sdk,unitlab
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: httpx>=0.27
23
+ Requires-Dist: tqdm>=4.60
24
+ Requires-Dist: typer>=0.9
25
+ Provides-Extra: dev
26
+ Requires-Dist: build>=1.0; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
28
+ Requires-Dist: pytest>=7.0; extra == 'dev'
29
+ Requires-Dist: respx>=0.21; extra == 'dev'
30
+ Requires-Dist: ruff>=0.4; extra == 'dev'
31
+ Requires-Dist: twine>=5.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ <p align="center">
35
+ <br>
36
+ <img src="https://unitlab-storage.s3.us-east-2.amazonaws.com/Logo.png" width="400"/>
37
+ <br>
38
+ <p>
39
+
40
+ <p align="center">
41
+ <a href="https://pypi.org/project/unitlab/">
42
+ <img alt="PyPI" src="https://img.shields.io/pypi/v/unitlab">
43
+ </a>
44
+ <a href="https://pypi.org/project/unitlab/">
45
+ <img alt="Python" src="https://img.shields.io/pypi/pyversions/unitlab">
46
+ </a>
47
+ <a href="https://github.com/teamunitlab/unitlab-sdk">
48
+ <img alt="Downloads" src="https://img.shields.io/pypi/dm/unitlab">
49
+ </a>
50
+ <a href="https://github.com/teamunitlab/unitlab-sdk/blob/main/LICENSE.md">
51
+ <img alt="License" src="https://img.shields.io/pypi/l/unitlab">
52
+ </a>
53
+ </p>
54
+
55
+ [Unitlab.ai](https://unitlab.ai/) is an AI-driven data annotation platform that automates the collection of raw data, facilitating collaboration with human annotators to produce highly accurate labels for your machine learning models. With our service, you can optimize work efficiency, improve data quality, and reduce costs.
56
+
57
+ ![](https://unitlab-storage.s3.us-east-2.amazonaws.com/unitlab.png)
58
+
59
+ # Unitlab Python SDK
60
+
61
+ Native Python and CLI access to Unitlab projects, Ontologies, Assets, datasets,
62
+ published versions, Batch Queues, Releases, cloud storage, and multimodal Data
63
+ Groups and Workflow Tasks.
64
+
65
+ ## Install
66
+
67
+ ```bash
68
+ pip install --upgrade unitlab
69
+ ```
70
+
71
+ Python 3.10 or newer is required.
72
+
73
+ ## Authenticate
74
+
75
+ Create an API key in Workspace settings, then use environment variables:
76
+
77
+ ```bash
78
+ export UNITLAB_API_KEY="YOUR_API_KEY"
79
+ export UNITLAB_API_URL="https://api.unitlab.ai" # optional
80
+ ```
81
+
82
+ Or configure the CLI once:
83
+
84
+ ```bash
85
+ unitlab configure --api-key YOUR_API_KEY
86
+ unitlab configure --api-url https://api.unitlab.ai
87
+ ```
88
+
89
+ You can also pass both values directly:
90
+
91
+ ```python
92
+ from unitlab import UnitlabClient
93
+
94
+ client = UnitlabClient(
95
+ api_key="YOUR_API_KEY",
96
+ api_url="https://api.unitlab.ai",
97
+ )
98
+ ```
99
+
100
+
101
+ ### 1. Upload multimodal data to a project
102
+
103
+ ```python
104
+ from unitlab import UnitlabClient
105
+
106
+ client = UnitlabClient()
107
+ project = client.projects.create("Medical review")
108
+ batch = project.upload("./multimodal-data")
109
+ status = batch.wait()
110
+
111
+ print(batch.uploaded, batch.batch_queue_id)
112
+ ```
113
+
114
+ The directory may mix images, video, audio, text, PDFs, DICOM, NIfTI, and NRRD.
115
+ One call creates one Batch Queue. Call `batch.wait()` when the next operation
116
+ depends on server-side processing.
117
+
118
+ ### 2. Curate in Assets, publish a dataset, and attach it
119
+
120
+ ```python
121
+ from unitlab import UnitlabClient
122
+
123
+ client = UnitlabClient()
124
+ project = client.projects.create("Quality review")
125
+
126
+ uploaded = client.assets.upload(
127
+ "./multimodal-data",
128
+ folder="Raw data",
129
+ tags=["incoming"],
130
+ )
131
+
132
+ dataset = client.datasets.create(
133
+ "Review set",
134
+ folder_ids=[uploaded.folder_id],
135
+ )
136
+ version = dataset.publish_version("Initial snapshot")
137
+
138
+ attached = client.attach_dataset(
139
+ project,
140
+ dataset,
141
+ version=version.version_number,
142
+ )
143
+
144
+ print(attached.created_count)
145
+ ```
146
+
147
+ Datasets are version-first. Editing a dataset creates Unpublished changes;
148
+ `publish_version()` freezes a version, and projects attach that published snapshot.
149
+
150
+ ### 3. Import existing cloud data
151
+
152
+ ```python
153
+ from unitlab import UnitlabClient
154
+
155
+ client = UnitlabClient()
156
+ project = client.projects.create("Cloud review")
157
+ storage = next(
158
+ item for item in client.cloud_storages.list() if item.name == "Production data"
159
+ )
160
+
161
+ batch = project.import_cloud(
162
+ storage,
163
+ ["incoming/study-001/"],
164
+ )
165
+ status = batch.wait()
166
+
167
+ print(batch.batch_queue_id)
168
+ ```
169
+
170
+ Directory paths end in `/`. Cloud credentials are never returned through the
171
+ SDK; list and browse responses expose only safe storage metadata.
172
+
173
+ ## Resource handles
174
+
175
+ Namespace entrypoints return typed resource handles:
176
+
177
+ ```python
178
+ project = client.projects.get("PROJECT_ID")
179
+ projects = client.projects.list()
180
+ dataset = client.datasets.get("DATASET_ID")
181
+ datasets = client.datasets.list()
182
+ folder = client.assets.folder("FOLDER_ID")
183
+ folders = client.assets.folders()
184
+ ```
185
+
186
+ ### Ontologies
187
+
188
+ ```python
189
+ from unitlab import OntologyStructure, RadioAttribute, Shape
190
+
191
+ structure = OntologyStructure()
192
+ cat = structure.add_object("Cat", Shape.BOUNDING_BOX)
193
+ colour = cat.add_attribute(RadioAttribute, "Colour", required=True)
194
+ colour.add_option("Black")
195
+ colour.add_option("White")
196
+
197
+ ontology = client.ontologies.create("Cat labels", structure=structure)
198
+ project = client.projects.create(
199
+ "Cat review",
200
+ ontology_hash=ontology.id,
201
+ )
202
+ ```
203
+
204
+ Use `client.ontologies.get()`, `client.ontologies.list()`, and
205
+ `ontology.save()` for the rest of the Ontology lifecycle. Project attachment
206
+ copies the Workspace Ontology so Unitlab can preserve project-specific version
207
+ history.
208
+
209
+ ### Projects and Batch Queues
210
+
211
+ ```python
212
+ projects = client.projects.list()
213
+ project = client.projects.get("PROJECT_ID")
214
+ project = client.projects.create("Road scenes")
215
+
216
+ batch = project.upload("./data", fps=2.0)
217
+
218
+ status = batch.status()
219
+ status = batch.wait(timeout=1800)
220
+
221
+ queues = project.batch_queues()
222
+ queue = project.batch_queue(batch.batch_queue_id)
223
+ items = queue.data()
224
+ status = queue.wait()
225
+ ```
226
+
227
+ `ProcessingStatus` exposes `total`, `completed`, `processing`, and `failed`.
228
+ Completion means `processing == 0`; a completed Batch Queue may still report
229
+ individual failures.
230
+
231
+ ### Data Units and project lifecycle
232
+
233
+ ```python
234
+ project.update(name="Road review v2", description="Second collection")
235
+
236
+ units = project.data_units(data_type="image", status="annotate")
237
+ unit = client.get_data_unit(project.id, units[0].id)
238
+
239
+ for unit in units:
240
+ print(unit.kind, unit.name, unit.status)
241
+ ```
242
+
243
+ A loose file is one `datasource` Data Unit. A Data Group is one `group` Data
244
+ Unit whose `items` contain its tile summaries; member files are not duplicated
245
+ in the top-level list. `project.delete()` soft-deletes the Project and schedules
246
+ the existing backend cleanup.
247
+
248
+ ### Assets and folders
249
+
250
+ ```python
251
+ folders = client.assets.folders()
252
+ folder = client.assets.create_folder("Raw data")
253
+ children = folder.children()
254
+ every_folder = client.assets.all_folders()
255
+ items = folder.list_items()
256
+
257
+ result = client.assets.upload("./images", folder_id=folder.id, tags=["train"])
258
+ asset = result.assets[0]
259
+
260
+ cloud_folder = client.assets.create_cloud_folder(
261
+ "Incoming",
262
+ "CLOUD_STORAGE_ID",
263
+ prefix="incoming/",
264
+ )
265
+ cloud_folder.sync_cloud()
266
+ ```
267
+
268
+ ### Datasets and published versions
269
+
270
+ ```python
271
+ dataset = client.datasets.create(
272
+ "Training set",
273
+ folder_ids=["FOLDER_ID"],
274
+ )
275
+
276
+ dataset.add_sources(asset_ids=["ASSET_ID"])
277
+ changes = dataset.unpublished_changes()
278
+ version = dataset.publish_version("Added edge cases")
279
+ versions = dataset.versions()
280
+ items = dataset.list_items(version=version.version_number)
281
+ ```
282
+
283
+ ### Workflow Tasks
284
+
285
+ ```python
286
+ workflow = project.workflow
287
+ annotate = workflow.get_stage(name="Annotate")
288
+
289
+ for task in annotate.get_tasks():
290
+ task.assign("USER_ID")
291
+ task.submit()
292
+ ```
293
+
294
+ Review Tasks provide `approve()` and `reject()`. Managers can use `move()` for
295
+ a direct stage override and `get_timeline()` to inspect Task history.
296
+
297
+ ### Attach data
298
+
299
+ ```python
300
+ preview = project.attach_preview(dataset_ids=[dataset.id])
301
+
302
+ result = project.attach(dataset_ids=[dataset.id])
303
+
304
+ # Attach an exact version instead of latest:
305
+ result = project.attach(
306
+ dataset_versions=[
307
+ {"dataset_id": dataset.id, "version_number": 2},
308
+ ]
309
+ )
310
+
311
+ for source in project.attached_sources():
312
+ print(source.name, source.detach_preview())
313
+ # source.detach() removes only the Project copy and keeps annotations.
314
+ ```
315
+
316
+ Video attachment may require `fps=`. Call `attach_preview()` when you need
317
+ counts before committing; `attach()` validates the same rule and raises an
318
+ actionable `ValidationError` if FPS is missing.
319
+
320
+ ### Cloud storage
321
+
322
+ ```python
323
+ storages = client.cloud_storages.list()
324
+ storage = storages[0]
325
+
326
+ for entry in storage.browse(prefix="incoming/"):
327
+ print(entry.name, entry.type, entry.size)
328
+
329
+ batch = project.import_cloud(
330
+ storage,
331
+ ["incoming/file.png", "incoming/study/"],
332
+ )
333
+ status = batch.wait()
334
+ ```
335
+
336
+ ### Data Groups
337
+
338
+ Let Unitlab suggest a filename pattern:
339
+
340
+ ```python
341
+ folder = client.assets.folder("FOLDER_ID")
342
+ grouped = folder.auto_group()
343
+ ```
344
+
345
+ Or compile a literal filename template:
346
+
347
+ ```python
348
+ from unitlab import tiles_from_template
349
+
350
+ config = tiles_from_template(
351
+ "{patient_id}_{view}",
352
+ tile_values={
353
+ "view": ["L_CC", "R_CC", "L_MLO", "R_MLO"],
354
+ },
355
+ )
356
+
357
+ estimate = folder.estimate_grouping(config)
358
+ grouped = folder.auto_group(config)
359
+ ```
360
+
361
+ For folders above 5,000 files or estimates above 1,000 groups, `auto_group()`
362
+ raises an actionable `ValidationError`. Split the source into smaller folders
363
+ and retry; the SDK does not return a job that will never run.
364
+
365
+ ### Releases
366
+
367
+ Releases are exported annotation snapshots. They are separate from Assets
368
+ datasets.
369
+
370
+ ```python
371
+ release = client.releases.create(
372
+ project,
373
+ export_type="UUEF",
374
+ split_ratios={"train": 80, "test": 20},
375
+ )
376
+
377
+ releases = client.releases.list()
378
+ release = client.releases.get(release.id)
379
+
380
+ annotation_path = release.download(split="train", dest="./release-annotations")
381
+ files_folder = release.download_files(dest="./release-files")
382
+ ```
383
+
384
+ Release item download tokens are persistent Unitlab URLs. For files stored in
385
+ customer cloud storage, the URL redirects to a signed target URL; only that target
386
+ URL is temporary.
387
+
388
+ ## CLI quick reference
389
+
390
+ ```bash
391
+ # Projects and Batch Queues
392
+ unitlab project create "Medical review" --ontology ONTOLOGY_ID
393
+ unitlab project list
394
+ unitlab project detail PROJECT_ID
395
+ unitlab project update PROJECT_ID --name "Medical review v2"
396
+ unitlab project data-units PROJECT_ID --data-type image
397
+ unitlab project data-unit PROJECT_ID DATA_UNIT_ID
398
+ unitlab project sources PROJECT_ID
399
+ unitlab project detach-source PROJECT_ID SOURCE_LINK_ID --preview
400
+ unitlab project upload PROJECT_ID --source ./data
401
+ unitlab batch-queue list PROJECT_ID
402
+ unitlab batch-queue detail PROJECT_ID BATCH_QUEUE_ID
403
+ unitlab batch-queue status PROJECT_ID BATCH_QUEUE_ID
404
+ unitlab batch-queue data PROJECT_ID BATCH_QUEUE_ID
405
+ unitlab batch-queue wait PROJECT_ID BATCH_QUEUE_ID --timeout 1800
406
+
407
+ # Cloud import and attach
408
+ unitlab project import-cloud PROJECT_ID CLOUD_STORAGE_ID incoming/study/
409
+ unitlab project attach PROJECT_ID --dataset DATASET_ID
410
+ unitlab project attach PROJECT_ID --dataset DATASET_ID --preview
411
+ unitlab project attach PROJECT_ID --dataset-version DATASET_ID:2
412
+
413
+ # Assets
414
+ unitlab assets upload ./data --folder "Raw data" --tag incoming
415
+
416
+ # Folders
417
+ unitlab folders create "Raw data"
418
+ unitlab folders create "Incoming" \
419
+ --cloud-storage CLOUD_STORAGE_ID --prefix incoming/
420
+ unitlab folders list
421
+ unitlab folders list --parent PARENT_FOLDER_ID
422
+ unitlab folders detail FOLDER_ID
423
+ unitlab assets upload ./data --folder-id FOLDER_ID
424
+ unitlab folders sync-cloud FOLDER_ID
425
+
426
+ # Data Groups
427
+ unitlab assets group FOLDER_ID --config grouping.json
428
+ unitlab assets group FOLDER_ID --config grouping.json --preview
429
+ unitlab assets group FOLDER_ID --preview
430
+ unitlab assets group FOLDER_ID \
431
+ --template '{patient_id}_{view}' \
432
+ --tile-values view=L_CC,R_CC,L_MLO,R_MLO
433
+
434
+ # Datasets
435
+ unitlab dataset list
436
+ unitlab dataset create "Training set" --folder FOLDER_ID
437
+ unitlab dataset detail DATASET_ID
438
+ unitlab dataset add-sources DATASET_ID --asset ASSET_ID
439
+ unitlab dataset unpublished-changes DATASET_ID
440
+ unitlab dataset publish DATASET_ID --title "Initial snapshot"
441
+ unitlab dataset versions DATASET_ID
442
+
443
+ # Releases
444
+ unitlab release create PROJECT_ID --format UUEF --splits train=100
445
+ unitlab release list
446
+ unitlab release detail RELEASE_ID
447
+ unitlab release download RELEASE_ID --split-type train --dest ./release-annotations
448
+
449
+ # Ontologies
450
+ unitlab ontology list
451
+ unitlab ontology list --title-like Medical --created-after 2026-01-01
452
+ unitlab ontology create "Medical labels" --structure ontology.json
453
+ unitlab ontology update ONTOLOGY_ID --title "Medical labels v2"
454
+
455
+ # Cloud storage
456
+ unitlab cloud list
457
+ unitlab cloud browse CLOUD_STORAGE_ID --prefix incoming/
458
+ ```
459
+
460
+ Run `unitlab COMMAND --help` for every option.
461
+
462
+ ## License
463
+
464
+ [MIT](LICENSE.md)