Skip to content

Commit 4cb1780

Browse files
author
Matt Sokoloff
committed
resolve converter issues
1 parent 98069c5 commit 4cb1780

File tree

8 files changed

+42
-27
lines changed

8 files changed

+42
-27
lines changed

labelbox/data/annotation_types/annotation.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from typing import Any, Dict, List, Union
22

3-
from pydantic.main import BaseModel
4-
53
from .classification import Checklist, Dropdown, Radio, Text
64
from .feature import FeatureSchema
75
from .geometry import Geometry

labelbox/data/annotation_types/classification/classification.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
from typing import Any, Dict, List
22

3-
from pydantic.main import BaseModel
3+
try:
4+
from typing import Literal
5+
except:
6+
from typing_extensions import Literal
47

8+
from pydantic import BaseModel, validator
59
from ..feature import FeatureSchema
610

711

12+
# TODO: Replace when pydantic adds support for unions that don't coerce types
13+
class _TempName(BaseModel):
14+
name: str
15+
16+
def dict(self, *args, **kwargs):
17+
res = super().dict(*args, **kwargs)
18+
res.pop('name')
19+
return res
20+
21+
822
class ClassificationAnswer(FeatureSchema):
923
"""
1024
- Represents a classification option.
@@ -19,8 +33,9 @@ class Radio(BaseModel):
1933
answer: ClassificationAnswer
2034

2135

22-
class Checklist(BaseModel):
36+
class Checklist(_TempName):
2337
""" A classification with many selected options allowed """
38+
name: Literal["checklist"] = "checklist"
2439
answer: List[ClassificationAnswer]
2540

2641

@@ -29,9 +44,10 @@ class Text(BaseModel):
2944
answer: str
3045

3146

32-
class Dropdown(BaseModel):
47+
class Dropdown(_TempName):
3348
"""
3449
- A classification with many selected options allowed .
3550
- This is not currently compatible with MAL.
3651
"""
52+
name: Literal["dropdown"] = "dropdown"
3753
answer: List[ClassificationAnswer]

labelbox/data/serialization/labelbox_v1/classification.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def to_common(self) -> Dropdown:
8282
def from_common(cls, dropdown: Dropdown, feature_schema_id: Cuid,
8383
**extra) -> "LBV1Dropdown":
8484
return cls(schema_id=feature_schema_id,
85-
answers=[
85+
answer=[
8686
LBV1ClassificationAnswer(
8787
schema_id=answer.feature_schema_id,
8888
title=answer.name,

labelbox/data/serialization/labelbox_v1/converter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def deserialize(json_data: Iterable[Dict[str, Any]]) -> LabelGenerator:
4545
Returns:
4646
LabelGenerator containing the export data.
4747
"""
48+
4849
def label_generator():
4950
for example in json_data:
5051
if 'frames' in example['Label']:
@@ -54,6 +55,7 @@ def label_generator():
5455
if example['Label']:
5556
# Don't construct empty dict
5657
yield LBV1Label(**example).to_common()
58+
5759
return LabelGenerator(data=label_generator())
5860

5961
@staticmethod

labelbox/data/serialization/labelbox_v1/objects.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
class LBV1ObjectBase(LBV1Feature):
1616
color: Optional[str] = None
1717
instanceURI: Optional[str] = None
18-
classifications: List[Union[LBV1Text, LBV1Radio, LBV1Dropdown, LBV1Checklist]] = []
18+
classifications: List[Union[LBV1Text, LBV1Radio, LBV1Dropdown,
19+
LBV1Checklist]] = []
20+
1921
def dict(self, *args, **kwargs):
2022
res = super().dict(*args, **kwargs)
2123
# This means these are not video frames ..

labelbox/data/serialization/ndjson/classification.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ def to_common(
165165
def lookup_subclassification(
166166
annotation: ClassificationAnnotation
167167
) -> Union[NDTextSubclass, NDChecklistSubclass, NDRadioSubclass]:
168-
if isinstance(annotation, Dropdown):
169-
raise TypeError("Dropdowns are not supported for MAL")
168+
if isinstance(annotation.value, Dropdown):
169+
raise TypeError("Dropdowns are not supported for MAL.")
170170
return {
171171
Text: NDTextSubclass,
172172
Checklist: NDChecklistSubclass,
@@ -213,13 +213,12 @@ def lookup_classification(
213213
annotation: Union[ClassificationAnnotation,
214214
VideoClassificationAnnotation]
215215
) -> Union[NDText, NDChecklist, NDRadio]:
216-
if isinstance(annotation, Dropdown):
217-
raise TypeError("Dropdowns are not supported for MAL")
216+
if isinstance(annotation.value, Dropdown):
217+
raise TypeError("Dropdowns are not supported for MAL.")
218218
return {
219219
Text: NDText,
220220
Checklist: NDChecklist,
221-
Radio: NDRadio,
222-
Dropdown: NDChecklist,
221+
Radio: NDRadio
223222
}.get(type(annotation.value))
224223

225224

labelbox/data/serialization/ndjson/label.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from itertools import groupby
23
from labelbox.data.annotation_types.classification.classification import Dropdown
34
from labelbox.data.annotation_types.metrics import ScalarMetric
@@ -17,6 +18,8 @@
1718
from .classification import NDChecklistSubclass, NDClassification, NDClassificationType, NDRadioSubclass
1819
from .objects import NDObject, NDObjectType
1920

21+
logger = logging.getLogger(__name__)
22+
2023

2124
class NDLabel(BaseModel):
2225
annotations: List[Union[NDObjectType, NDClassificationType, NDMetricType]]
@@ -103,11 +106,6 @@ def _create_non_video_annotations(cls, label: Label):
103106
]
104107
for annotation in non_video_annotations:
105108
if isinstance(annotation, ClassificationAnnotation):
106-
if isinstance(annotation.value, Dropdown):
107-
raise ValueError(
108-
"Dropdowns are not supported by the NDJson format."
109-
" Please filter out Dropdown annotations before converting."
110-
)
111109
yield NDClassification.from_common(annotation, label.data)
112110
elif isinstance(annotation, ObjectAnnotation):
113111
yield NDObject.from_common(annotation, label.data)

tests/data/serialization/labelbox_v1/test_image.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55
from labelbox.data.serialization.labelbox_v1.converter import LBV1Converter
66

77

8-
9-
@pytest.mark.parametrize(
10-
"file_path",
11-
[
12-
'tests/data/assets/labelbox_v1/highly_nested_image.json',
13-
'tests/data/assets/labelbox_v1/image_export.json'
14-
])
8+
@pytest.mark.parametrize("file_path", [
9+
'tests/data/assets/labelbox_v1/highly_nested_image.json',
10+
'tests/data/assets/labelbox_v1/image_export.json'
11+
])
1512
def test_image(file_path):
1613
with open(file_path, 'r') as file:
1714
payload = json.load(file)
@@ -30,10 +27,13 @@ def test_image(file_path):
3027
# We don't add a classification key to the payload if there is no classifications.
3128
annotation_a.pop('classifications')
3229

33-
if isinstance(annotation_b.get('classifications'), list) and len(annotation_b['classifications']):
30+
if isinstance(annotation_b.get('classifications'),
31+
list) and len(annotation_b['classifications']):
3432
if isinstance(annotation_b['classifications'][0], list):
35-
annotation_b['classifications'] = annotation_b['classifications'][0]
33+
annotation_b['classifications'] = annotation_b[
34+
'classifications'][0]
3635

3736
assert annotation_a == annotation_b
3837

38+
3939
# After check the nd serializer on this shit.. It should work for almost everything (except the other horse shit..)

0 commit comments

Comments
 (0)