Skip to content

Commit a712d2b

Browse files
authored
Merge pull request #671 from Labelbox/develop
3.26.0
2 parents 65f4dfe + 900f230 commit a712d2b

File tree

6 files changed

+104
-11
lines changed

6 files changed

+104
-11
lines changed

CHANGELOG.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
# Changelog
2+
3+
# Version 3.26.0 (2022-08-12)
4+
## Added
5+
* `Batch.delete()` which will delete an existing `Batch`
6+
* `Batch.delete_labels()` which will delete all `Label`’s created after a `Project`’s mode has been set to batch.
7+
* Note: Does not include labels that were imported via model-assisted labeling or label imports
8+
* Support for creating model config when creating a model run
9+
* `RAW_TEXT` and `TEXT_FILE` attachment types to replace the `TEXT` type.
10+
211
# Version 3.25.3 (2022-08-10)
312
## Fixed
413
* Label export will continue polling if the downloadUrl is None
@@ -29,7 +38,7 @@
2938
* `Batch.export_data_rows(include_metadata=True)`
3039
* `Dataset.export_data_rows(include_metadata=True)`
3140
* `Project.export_queued_data_rows(include_metadata=True)`
32-
* `VideoObjectAnnotation` has `segment_index` to group video annotations into video segments
41+
* `VideoObjectAnnotation` has `segment_index` to group video annotations into video segments
3342

3443
## Removed
3544
* `Project.video_label_generator`. Use `Project.label_generator` instead.
@@ -40,7 +49,7 @@
4049
* 150,000 rows per upload without metadata
4150
* 30,000 rows per upload with metadata
4251

43-
52+
4453
# Version 3.24.1 (2022-07-07)
4554
## Updated
4655
* Added `refresh_ontology()` as part of create/update/delete metadata schema functions
@@ -657,4 +666,4 @@ Changelog not maintained before version 2.2.
657666

658667
### Changed
659668
* `Model.create_model_run()`
660-
* Add training metadata config as a model run creation param
669+
* Add training metadata config as a model run creation param

labelbox/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name = "labelbox"
2-
__version__ = "3.25.3"
2+
__version__ = "3.26.0"
33

44
from labelbox.client import Client
55
from labelbox.schema.project import Project

labelbox/data/serialization/coco/instance_dataset.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,14 @@ def mask_to_coco_object_annotation(
2828
xmin, ymin, xmax, ymax = shapely.bounds
2929
# Iterate over polygon once or multiple polygon for each item
3030
area = shapely.area
31-
if shapely.type == 'Polygon':
32-
shapely = [shapely]
3331

3432
return COCOObjectAnnotation(
3533
id=annot_idx,
3634
image_id=image_id,
3735
category_id=category_id,
3836
segmentation=[
39-
np.array(s.exterior.coords).ravel().tolist() for s in shapely
37+
np.array(s.exterior.coords).ravel().tolist()
38+
for s in ([shapely] if shapely.type == "Polygon" else shapely.geoms)
4039
],
4140
area=area,
4241
bbox=[xmin, ymin, xmax - xmin, ymax - ymin],

labelbox/schema/asset_attachment.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class AssetAttachment(DbObject):
99
""" Asset attachment provides extra context about an asset while labeling.
1010
1111
Attributes:
12-
attachment_type (str): IMAGE, VIDEO, TEXT, IMAGE_OVERLAY, or HTML
12+
attachment_type (str): IMAGE, VIDEO, IMAGE_OVERLAY, HTML, RAW_TEXT, or TEXT_URL. TEXT attachment type is deprecated.
1313
attachment_value (str): URL to an external file or a string of text
1414
"""
1515

@@ -19,6 +19,8 @@ class AttachmentType(Enum):
1919
TEXT = "TEXT"
2020
IMAGE_OVERLAY = "IMAGE_OVERLAY"
2121
HTML = "HTML"
22+
RAW_TEXT = "RAW_TEXT"
23+
TEXT_URL = "TEXT_URL"
2224

2325
for topic in AttachmentType:
2426
vars()[topic.name] = topic.value

labelbox/schema/batch.py

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,15 @@ def remove_queued_data_rows(self) -> None:
6868

6969
project_id_param = "projectId"
7070
batch_id_param = "batchId"
71-
self.client.execute("""mutation ArchiveBatchPyApi($%s: ID!, $%s: ID!) {
72-
project(where: {id: $%s}) { archiveBatch(batchId: $%s) { id archivedAt } }
71+
self.client.execute(
72+
"""mutation RemoveQueuedDataRowsFromBatchPyApi($%s: ID!, $%s: ID!) {
73+
project(where: {id: $%s}) { removeQueuedDataRowsFromBatch(batchId: $%s) { id } }
7374
}""" % (project_id_param, batch_id_param, project_id_param,
7475
batch_id_param), {
7576
project_id_param: self.project_id,
7677
batch_id_param: self.uid
7778
},
78-
experimental=True)
79+
experimental=True)
7980

8081
def export_data_rows(self,
8182
timeout_seconds=120,
@@ -125,3 +126,50 @@ def export_data_rows(self,
125126
logger.debug("Batch '%s' data row export, waiting for server...",
126127
self.uid)
127128
time.sleep(sleep_time)
129+
130+
def delete(self) -> None:
131+
""" Deletes the given batch.
132+
133+
Note: Batch deletion for batches that has labels is forbidden.
134+
135+
Args:
136+
batch (Batch): Batch to remove queued data rows from
137+
"""
138+
139+
project_id_param = "projectId"
140+
batch_id_param = "batchId"
141+
self.client.execute("""mutation DeleteBatchPyApi($%s: ID!, $%s: ID!) {
142+
project(where: {id: $%s}) { deleteBatch(batchId: $%s) { deletedBatchId } }
143+
}""" % (project_id_param, batch_id_param, project_id_param,
144+
batch_id_param), {
145+
project_id_param: self.project_id,
146+
batch_id_param: self.uid
147+
},
148+
experimental=True)
149+
150+
def delete_labels(self, set_labels_as_template=False) -> None:
151+
""" Deletes labels that were created for data rows in the batch.
152+
153+
Args:
154+
batch (Batch): Batch to remove queued data rows from
155+
set_labels_as_template (bool): When set to true, the deleted labels will be kept as templates.
156+
"""
157+
158+
project_id_param = "projectId"
159+
batch_id_param = "batchId"
160+
type_param = "type"
161+
res = self.client.execute(
162+
"""mutation DeleteBatchLabelsPyApi($%s: ID!, $%s: ID!, $%s: DeleteBatchLabelsType!) {
163+
project(where: {id: $%s}) { deleteBatchLabels(batchId: $%s, data:{ type: $%s }) { deletedLabelIds } }
164+
}""" % (project_id_param, batch_id_param, type_param, project_id_param,
165+
batch_id_param, type_param), {
166+
project_id_param:
167+
self.project_id,
168+
batch_id_param:
169+
self.uid,
170+
type_param:
171+
"RequeueDataWithLabelAsTemplate"
172+
if set_labels_as_template else "RequeueData"
173+
},
174+
experimental=True)
175+
return res

tests/integration/test_batch.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ def test_archive_batch(configured_project: Project, small_dataset: Dataset):
5050
assert len(exported_data_rows) == 0
5151

5252

53+
def test_delete(configured_project: Project, small_dataset: Dataset):
54+
data_rows = [dr.uid for dr in list(small_dataset.export_data_rows())]
55+
configured_project.update(queue_mode=Project.QueueMode.Batch)
56+
batch = configured_project.create_batch("batch to delete", data_rows)
57+
batch.delete()
58+
59+
assert len(list(configured_project.batches())) == 0
60+
61+
5362
def test_batch_project(configured_project: Project, small_dataset: Dataset):
5463
data_rows = [dr.uid for dr in list(small_dataset.export_data_rows())]
5564
configured_project.update(queue_mode=Project.QueueMode.Batch)
@@ -80,3 +89,29 @@ def test_export_data_rows(configured_project: Project, dataset: Dataset):
8089

8190
assert len(result) == n_data_rows
8291
assert set(data_rows) == set(exported_data_rows)
92+
93+
94+
@pytest.mark.skip(
95+
reason="Test cannot be used effectively with MAL/LabelImport. \
96+
Fix/Unskip after resolving deletion with MAL/LabelImport")
97+
def test_delete_labels(configured_project_with_label):
98+
project, dataset, _, _ = configured_project_with_label
99+
100+
data_rows = [dr.uid for dr in list(dataset.export_data_rows())]
101+
project.update(queue_mode=Project.QueueMode.Batch)
102+
batch = project.create_batch("batch to delete labels", data_rows)
103+
104+
105+
@pytest.mark.skip(
106+
reason="Test cannot be used effectively with MAL/LabelImport. \
107+
Fix/Unskip after resolving deletion with MAL/LabelImport")
108+
def test_delete_labels_with_templates(configured_project: Project,
109+
small_dataset: Dataset):
110+
data_rows = [dr.uid for dr in list(small_dataset.export_data_rows())]
111+
configured_project.update(queue_mode=Project.QueueMode.Batch)
112+
batch = configured_project.create_batch(
113+
"batch to delete labels w templates", data_rows)
114+
exported_data_rows = list(batch.export_data_rows())
115+
res = batch.delete_labels(labels_as_template=True)
116+
exported_data_rows = list(batch.export_data_rows())
117+
assert len(exported_data_rows) == 5

0 commit comments

Comments
 (0)