unitlab 2.5.0__tar.gz → 3.0.0__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.0/PKG-INFO +460 -0
  2. unitlab-3.0.0/README.md +427 -0
  3. {unitlab-2.5.0 → unitlab-3.0.0}/pyproject.toml +5 -3
  4. unitlab-3.0.0/src/unitlab/__init__.py +102 -0
  5. unitlab-3.0.0/src/unitlab/__main__.py +3 -0
  6. unitlab-3.0.0/src/unitlab/_downloader.py +93 -0
  7. unitlab-3.0.0/src/unitlab/_grouping.py +75 -0
  8. unitlab-3.0.0/src/unitlab/_http.py +160 -0
  9. unitlab-3.0.0/src/unitlab/_uploader.py +418 -0
  10. unitlab-3.0.0/src/unitlab/_waiter.py +80 -0
  11. unitlab-3.0.0/src/unitlab/cli.py +1384 -0
  12. unitlab-3.0.0/src/unitlab/client.py +91 -0
  13. {unitlab-2.5.0 → unitlab-3.0.0}/src/unitlab/exceptions.py +23 -14
  14. unitlab-3.0.0/src/unitlab/ontology.py +273 -0
  15. unitlab-3.0.0/src/unitlab/py.typed +0 -0
  16. unitlab-3.0.0/src/unitlab/resources/__init__.py +29 -0
  17. unitlab-3.0.0/src/unitlab/resources/_base.py +41 -0
  18. unitlab-3.0.0/src/unitlab/resources/assets.py +302 -0
  19. unitlab-3.0.0/src/unitlab/resources/cloud.py +84 -0
  20. unitlab-3.0.0/src/unitlab/resources/datasets.py +261 -0
  21. unitlab-3.0.0/src/unitlab/resources/embeddings.py +127 -0
  22. unitlab-3.0.0/src/unitlab/resources/ontologies.py +129 -0
  23. unitlab-3.0.0/src/unitlab/resources/projects.py +611 -0
  24. unitlab-3.0.0/src/unitlab/resources/releases.py +139 -0
  25. unitlab-3.0.0/src/unitlab/resources/workflow.py +349 -0
  26. unitlab-3.0.0/src/unitlab/types.py +153 -0
  27. unitlab-3.0.0/tests/test_cli.py +558 -0
  28. unitlab-3.0.0/tests/test_client.py +678 -0
  29. unitlab-3.0.0/tests/test_downloader.py +93 -0
  30. unitlab-3.0.0/tests/test_embeddings.py +373 -0
  31. unitlab-3.0.0/tests/test_http.py +69 -0
  32. unitlab-3.0.0/tests/test_uploader.py +545 -0
  33. unitlab-2.5.0/.claude/settings.local.json +0 -49
  34. unitlab-2.5.0/PKG-INFO +0 -213
  35. unitlab-2.5.0/README.md +0 -179
  36. unitlab-2.5.0/src/unitlab/__init__.py +0 -7
  37. unitlab-2.5.0/src/unitlab/__main__.py +0 -3
  38. unitlab-2.5.0/src/unitlab/cli.py +0 -127
  39. unitlab-2.5.0/src/unitlab/client.py +0 -562
  40. {unitlab-2.5.0 → unitlab-3.0.0}/.gitignore +0 -0
  41. {unitlab-2.5.0 → unitlab-3.0.0}/LICENSE.md +0 -0
  42. {unitlab-2.5.0 → unitlab-3.0.0}/src/unitlab/_config.py +0 -0
unitlab-3.0.0/PKG-INFO ADDED
@@ -0,0 +1,460 @@
1
+ Metadata-Version: 2.4
2
+ Name: unitlab
3
+ Version: 3.0.0
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")
381
+ files_folder = release.download_files(dest="./release-files")
382
+ ```
383
+
384
+ ## CLI quick reference
385
+
386
+ ```bash
387
+ # Projects and Batch Queues
388
+ unitlab project create "Medical review" --ontology ONTOLOGY_ID
389
+ unitlab project list
390
+ unitlab project detail PROJECT_ID
391
+ unitlab project update PROJECT_ID --name "Medical review v2"
392
+ unitlab project data-units PROJECT_ID --data-type image
393
+ unitlab project data-unit PROJECT_ID DATA_UNIT_ID
394
+ unitlab project sources PROJECT_ID
395
+ unitlab project detach-source PROJECT_ID SOURCE_LINK_ID --preview
396
+ unitlab project upload PROJECT_ID --source ./data
397
+ unitlab batch-queue list PROJECT_ID
398
+ unitlab batch-queue detail PROJECT_ID BATCH_QUEUE_ID
399
+ unitlab batch-queue status PROJECT_ID BATCH_QUEUE_ID
400
+ unitlab batch-queue data PROJECT_ID BATCH_QUEUE_ID
401
+ unitlab batch-queue wait PROJECT_ID BATCH_QUEUE_ID --timeout 1800
402
+
403
+ # Cloud import and attach
404
+ unitlab project import-cloud PROJECT_ID CLOUD_STORAGE_ID incoming/study/
405
+ unitlab project attach PROJECT_ID --dataset DATASET_ID
406
+ unitlab project attach PROJECT_ID --dataset DATASET_ID --preview
407
+ unitlab project attach PROJECT_ID --dataset-version DATASET_ID:2
408
+
409
+ # Assets
410
+ unitlab assets upload ./data --folder "Raw data" --tag incoming
411
+
412
+ # Folders
413
+ unitlab folders create "Raw data"
414
+ unitlab folders create "Incoming" \
415
+ --cloud-storage CLOUD_STORAGE_ID --prefix incoming/
416
+ unitlab folders list
417
+ unitlab folders list --parent PARENT_FOLDER_ID
418
+ unitlab folders detail FOLDER_ID
419
+ unitlab assets upload ./data --folder-id FOLDER_ID
420
+ unitlab folders sync-cloud FOLDER_ID
421
+
422
+ # Data Groups
423
+ unitlab assets group FOLDER_ID --config grouping.json
424
+ unitlab assets group FOLDER_ID --config grouping.json --preview
425
+ unitlab assets group FOLDER_ID --preview
426
+ unitlab assets group FOLDER_ID \
427
+ --template '{patient_id}_{view}' \
428
+ --tile-values view=L_CC,R_CC,L_MLO,R_MLO
429
+
430
+ # Datasets
431
+ unitlab dataset list
432
+ unitlab dataset create "Training set" --folder FOLDER_ID
433
+ unitlab dataset detail DATASET_ID
434
+ unitlab dataset add-sources DATASET_ID --asset ASSET_ID
435
+ unitlab dataset unpublished-changes DATASET_ID
436
+ unitlab dataset publish DATASET_ID --title "Initial snapshot"
437
+ unitlab dataset versions DATASET_ID
438
+
439
+ # Releases
440
+ unitlab release create PROJECT_ID --format UUEF --splits train=100
441
+ unitlab release list
442
+ unitlab release detail RELEASE_ID
443
+ unitlab release download RELEASE_ID --split-type train
444
+
445
+ # Ontologies
446
+ unitlab ontology list
447
+ unitlab ontology list --title-like Medical --created-after 2026-01-01
448
+ unitlab ontology create "Medical labels" --structure ontology.json
449
+ unitlab ontology update ONTOLOGY_ID --title "Medical labels v2"
450
+
451
+ # Cloud storage
452
+ unitlab cloud list
453
+ unitlab cloud browse CLOUD_STORAGE_ID --prefix incoming/
454
+ ```
455
+
456
+ Run `unitlab COMMAND --help` for every option.
457
+
458
+ ## License
459
+
460
+ [MIT](LICENSE.md)