Skip to content

Commit 2a8f01d

Browse files
author
Matt Sokoloff
committed
format
1 parent dd67d5b commit 2a8f01d

File tree

22 files changed

+1230
-414
lines changed

22 files changed

+1230
-414
lines changed

labelbox/data/annotation_types/data/raster.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ def validate_args(cls, values):
7373
uid = values.get('uid')
7474
if uid == file_path == im_bytes == url == None and arr is None:
7575
raise ValidationError(
76-
"One of `file_path`, `im_bytes`, `url`, `uid` or `arr` required.")
76+
"One of `file_path`, `im_bytes`, `url`, `uid` or `arr` required."
77+
)
7778
if arr is not None:
7879
if arr.dtype != np.uint8:
7980
raise ValidationError(
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Optional
2-
from pydantic import BaseModel
2+
3+
from pydantic import BaseModel, ValidationError, root_validator
34

45

56
class DataRowRef(BaseModel):
@@ -11,6 +12,10 @@ class FeatureSchemaRef(BaseModel):
1112
display_name: Optional[str] = None
1213
schema_id: Optional[str] = None
1314

14-
# TODO: Validate that one of these is set..
15-
16-
15+
@root_validator
16+
def must_set_one(cls, values):
17+
if values['schema_id'] is None and values['display_name'] is None:
18+
raise ValidationError(
19+
"Must set either schema_id or display name for all feature schemas"
20+
)
21+
return values
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
from .labelbox_v1 import LBV1Converter
2+
from .ndjson import NDJsonConverter

labelbox/data/serialization/labelbox_v1/classifications.py

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
from typing import List, Union
22

3-
from pydantic.main import BaseModel
4-
from labelbox.data.annotation_types.classification.classification import Dropdown
5-
from labelbox.data.annotation_types.annotation import AnnotationType, ClassificationAnnotation
6-
3+
from labelbox.data.annotation_types.annotation import (AnnotationType,
4+
ClassificationAnnotation)
5+
from labelbox.data.annotation_types.classification import (CheckList,
6+
ClassificationAnswer,
7+
Radio, Text)
8+
from labelbox.data.annotation_types.classification.classification import \
9+
Dropdown
710
from labelbox.data.serialization.labelbox_v1.feature import LBV1Feature
8-
from labelbox.data.annotation_types.classification import Text, Radio, CheckList, ClassificationAnswer
11+
from pydantic.main import BaseModel
912

1013

1114
class LBV1ClassificationAnswer(LBV1Feature):
1215
...
1316

17+
1418
class LBV1Radio(LBV1Feature):
1519
answer: LBV1ClassificationAnswer
1620

@@ -25,14 +29,13 @@ def to_common(self):
2529

2630
@classmethod
2731
def from_common(cls, radio: Radio, schema_id: str, **extra) -> "LBV1Radio":
28-
return cls(
29-
schema_id=schema_id,
30-
answer=LBV1ClassificationAnswer(
31-
schema_id=radio.answer.schema_id,
32-
title=radio.answer.display_name,
33-
value=radio.answer.extra['value'],
34-
feature_id=radio.answer.extra['feature_id']),
35-
**extra)
32+
return cls(schema_id=schema_id,
33+
answer=LBV1ClassificationAnswer(
34+
schema_id=radio.answer.schema_id,
35+
title=radio.answer.display_name,
36+
value=radio.answer.extra['value'],
37+
feature_id=radio.answer.extra['feature_id']),
38+
**extra)
3639

3740

3841
class LBV1Checklist(LBV1Feature):
@@ -51,16 +54,16 @@ def to_common(self):
5154
@classmethod
5255
def from_common(cls, checklist: CheckList, schema_id: str,
5356
**extra) -> "LBV1Checklist":
54-
return cls(
55-
schema_id=schema_id,
56-
answers=[
57-
LBV1ClassificationAnswer(schema_id=answer.schema_id,
58-
title=answer.display_name,
59-
value=answer.extra['value'],
60-
feature_id=answer.extra['feature_id'])
61-
for answer in checklist.answer
62-
],
63-
**extra)
57+
return cls(schema_id=schema_id,
58+
answers=[
59+
LBV1ClassificationAnswer(
60+
schema_id=answer.schema_id,
61+
title=answer.display_name,
62+
value=answer.extra['value'],
63+
feature_id=answer.extra['feature_id'])
64+
for answer in checklist.answer
65+
],
66+
**extra)
6467

6568

6669
class LBV1Text(LBV1Feature):
@@ -90,7 +93,11 @@ def to_common(self):
9093
classifications = [
9194
ClassificationAnnotation(value=classification.to_common(),
9295
classifications=[],
93-
display_name=classification.title, extra = {'value': classification.value, 'feature_id' : classification.feature_id})
96+
display_name=classification.title,
97+
extra={
98+
'value': classification.value,
99+
'feature_id': classification.feature_id
100+
})
94101
for classification in self.classifications
95102
]
96103
return classifications

labelbox/data/serialization/labelbox_v1/converter.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414

1515
class LBV1Converter:
16+
1617
@staticmethod
1718
def deserialize_video(json_data: Iterable[Dict[str, Any]], client):
1819
"""
@@ -24,11 +25,15 @@ def deserialize_video(json_data: Iterable[Dict[str, Any]], client):
2425

2526
@staticmethod
2627
def deserialize(json_data: Iterable[Dict[str, Any]]) -> LabelCollection:
28+
2729
def label_generator():
2830
for example in json_data:
2931
if 'frames' in example['Label']:
30-
raise ValueError("Use `LBV1Converter.deserialize_video` to process video")
32+
raise ValueError(
33+
"Use `LBV1Converter.deserialize_video` to process video"
34+
)
3135
yield LBV1Label(**example).to_common()
36+
3237
return LabelCollection(data=label_generator())
3338

3439
@staticmethod
@@ -41,6 +46,7 @@ def serialize(label_collection: LabelCollection,
4146

4247

4348
class VideoIterator:
49+
4450
def __init__(self, examples, client):
4551
self.queue = Queue(20)
4652
self.n_iters = len(examples)

labelbox/data/serialization/labelbox_v1/feature.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,3 @@ def dict(self, *args, **kwargs):
2424

2525
class Config:
2626
allow_population_by_field_name = True
27-

labelbox/data/serialization/labelbox_v1/label.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -49,30 +49,31 @@ def to_common(self):
4949
]
5050

5151
objects = [
52-
VideoObjectAnnotation(value=obj.to_common(),
53-
keyframe=obj.keyframe,
54-
classifications=[
55-
ClassificationAnnotation(
56-
value=cls.to_common(),
57-
schema_id=cls.schema_id,
58-
display_name=cls.title,
59-
extra={
60-
'feature_id': cls.feature_id,
61-
'title': cls.title,
62-
'value': cls.value,
63-
'keyframe': getattr(cls, 'keyframe' , None)
64-
}) for cls in obj.classifications
65-
],
66-
display_name=obj.title,
67-
frame=self.frame_number,
68-
alternative_name=obj.value,
69-
schema_id=obj.schema_id,
70-
extra={
71-
'value' : obj.value,
72-
'instanceURI': obj.instanceURI,
73-
'color': obj.color,
74-
'feature_id': obj.feature_id,
75-
}) for obj in self.objects
52+
VideoObjectAnnotation(
53+
value=obj.to_common(),
54+
keyframe=obj.keyframe,
55+
classifications=[
56+
ClassificationAnnotation(
57+
value=cls.to_common(),
58+
schema_id=cls.schema_id,
59+
display_name=cls.title,
60+
extra={
61+
'feature_id': cls.feature_id,
62+
'title': cls.title,
63+
'value': cls.value,
64+
'keyframe': getattr(cls, 'keyframe', None)
65+
}) for cls in obj.classifications
66+
],
67+
display_name=obj.title,
68+
frame=self.frame_number,
69+
alternative_name=obj.value,
70+
schema_id=obj.schema_id,
71+
extra={
72+
'value': obj.value,
73+
'instanceURI': obj.instanceURI,
74+
'color': obj.color,
75+
'feature_id': obj.feature_id,
76+
}) for obj in self.objects
7677
]
7778
return [*classifications, *objects]
7879

@@ -108,7 +109,6 @@ class Review(BaseModel):
108109
label_id: str = Field(..., alias="labelId")
109110

110111

111-
112112
class LBV1Label(BaseModel):
113113
label: Union[_LBV1Label, List[_LBV1LabelVideo]] = Field(..., alias='Label')
114114
data_row_id: str = Field(..., alias="DataRow ID")
@@ -163,8 +163,6 @@ def to_common(self) -> Label:
163163
else:
164164
annotations = self.label.to_common()
165165

166-
167-
168166
return Label(
169167
data=self.construct_data_ref(is_video),
170168
annotations=annotations,
@@ -195,7 +193,6 @@ def from_common(cls, label: Label, signer: Callable):
195193
else:
196194
label_ = _LBV1Label.from_common(label.annotations)
197195

198-
199196
return LBV1Label(label=label_,
200197
data_row_id=label.data.uid,
201198
row_data=label.data.create_url(signer),

labelbox/data/serialization/labelbox_v1/objects.py

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from typing import Any, List, Optional, Union
22

3-
from labelbox.data.annotation_types.annotation import (
4-
AnnotationType, ClassificationAnnotation, ObjectAnnotation)
3+
from labelbox.data.annotation_types.annotation import (AnnotationType,
4+
ClassificationAnnotation,
5+
ObjectAnnotation)
56
from labelbox.data.annotation_types.data.raster import RasterData
67
from labelbox.data.annotation_types.geometry.line import Line
78
from labelbox.data.annotation_types.geometry.mask import Mask
@@ -181,27 +182,27 @@ class LBV1Objects(BaseModel):
181182

182183
def to_common(self):
183184
objects = [
184-
ObjectAnnotation(value=obj.to_common(),
185-
classifications=[
186-
ClassificationAnnotation(
187-
value=cls.to_common(),
188-
schema_id=cls.schema_id,
189-
display_name=cls.title,
190-
extra={
191-
'feature_id': cls.feature_id,
192-
'title': cls.title,
193-
'value': cls.value
194-
}) for cls in obj.classifications
195-
],
196-
display_name=obj.title,
197-
schema_id=obj.schema_id,
198-
extra={
199-
'instanceURI': obj.instanceURI,
200-
'color': obj.color,
201-
'feature_id': obj.feature_id,
202-
'value': obj.value,
203-
#'keyframe' : getattr(obj, 'keyframe', None)
204-
}) for obj in self.objects
185+
ObjectAnnotation(
186+
value=obj.to_common(),
187+
classifications=[
188+
ClassificationAnnotation(value=cls.to_common(),
189+
schema_id=cls.schema_id,
190+
display_name=cls.title,
191+
extra={
192+
'feature_id': cls.feature_id,
193+
'title': cls.title,
194+
'value': cls.value
195+
}) for cls in obj.classifications
196+
],
197+
display_name=obj.title,
198+
schema_id=obj.schema_id,
199+
extra={
200+
'instanceURI': obj.instanceURI,
201+
'color': obj.color,
202+
'feature_id': obj.feature_id,
203+
'value': obj.value,
204+
#'keyframe' : getattr(obj, 'keyframe', None)
205+
}) for obj in self.objects
205206
]
206207
return objects
207208

@@ -217,9 +218,12 @@ def from_common(cls, annotations: List[AnnotationType]) -> "LBV1Objects":
217218
annotation.classifications).classifications
218219

219220
objects.append(
220-
obj.from_common(annotation.value, subclasses,
221-
annotation.schema_id,
222-
annotation.display_name, {'keyframe' : getattr(annotation, 'keyframe' , None), ** annotation.extra}))
221+
obj.from_common(
222+
annotation.value, subclasses, annotation.schema_id,
223+
annotation.display_name, {
224+
'keyframe': getattr(annotation, 'keyframe', None),
225+
**annotation.extra
226+
}))
223227

224228
else:
225229
raise TypeError(f"Unexpected type {type(annotation.value)}")

labelbox/data/serialization/ndjson/base.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
2-
31
from uuid import UUID, uuid4
42
from pydantic import BaseModel, validator
53

@@ -12,6 +10,7 @@ class DataRow(BaseModel):
1210
id: str
1311
# TODO: If datarow.id is None. Then we will throw a nice error asking users to use our upload to dataset function.
1412

13+
1514
class NDJsonBase(BaseModel):
1615
uuid: str = None
1716
dataRow: DataRow
@@ -20,7 +19,6 @@ class NDJsonBase(BaseModel):
2019
def set_id(cls, v):
2120
return v or str(uuid4())
2221

23-
2422
class Config:
2523
#alias_generator = to_camel
2624
allow_population_by_field_name = True
@@ -29,5 +27,3 @@ class Config:
2927
class NDAnnotation(NDJsonBase):
3028
schemaId: str
3129
# TODO: If schema.id is None. Then we will throw a nice error asking users to use our assign schema id function.
32-
33-

0 commit comments

Comments
 (0)