Skip to content

Commit ad2223c

Browse files
chore: lint
1 parent 9afd82d commit ad2223c

File tree

8 files changed

+714
-395
lines changed

8 files changed

+714
-395
lines changed

examples/annotation_import/audio.ipynb

Lines changed: 570 additions & 352 deletions
Large diffs are not rendered by default.

libs/labelbox/src/labelbox/data/annotation_types/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
__all__ = [
6868
# Geometry
6969
"Line",
70-
"Point",
70+
"Point",
7171
"Mask",
7272
"Polygon",
7373
"Rectangle",

libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,3 @@ class ClassificationAnnotation(
7474

7575
value: Union[Text, Checklist, Radio]
7676
message_id: Optional[str] = None
77-

libs/labelbox/src/labelbox/data/annotation_types/label.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,22 @@ def validate_data(cls, data):
6969
def object_annotations(self) -> List[ObjectAnnotation]:
7070
return self._get_annotations_by_type(ObjectAnnotation)
7171

72-
def classification_annotations(self) -> List[Union[ClassificationAnnotation, TemporalClassificationText, TemporalClassificationQuestion]]:
73-
return self._get_annotations_by_type((ClassificationAnnotation, TemporalClassificationText, TemporalClassificationQuestion))
72+
def classification_annotations(
73+
self,
74+
) -> List[
75+
Union[
76+
ClassificationAnnotation,
77+
TemporalClassificationText,
78+
TemporalClassificationQuestion,
79+
]
80+
]:
81+
return self._get_annotations_by_type(
82+
(
83+
ClassificationAnnotation,
84+
TemporalClassificationText,
85+
TemporalClassificationQuestion,
86+
)
87+
)
7488

7589
def _get_annotations_by_type(self, annotation_type):
7690
return [
@@ -112,13 +126,26 @@ def frame_annotations(
112126
(VideoObjectAnnotation, VideoClassificationAnnotation),
113127
):
114128
frame_dict[annotation.frame].append(annotation)
115-
elif isinstance(annotation, (TemporalClassificationText, TemporalClassificationQuestion)):
129+
elif isinstance(
130+
annotation,
131+
(TemporalClassificationText, TemporalClassificationQuestion),
132+
):
116133
# For temporal annotations with multiple values/answers, use first frame
117-
if isinstance(annotation, TemporalClassificationText) and annotation.value:
118-
frame_dict[annotation.value[0][0]].append(annotation) # value[0][0] is start_frame
119-
elif isinstance(annotation, TemporalClassificationQuestion) and annotation.value:
134+
if (
135+
isinstance(annotation, TemporalClassificationText)
136+
and annotation.value
137+
):
138+
frame_dict[annotation.value[0][0]].append(
139+
annotation
140+
) # value[0][0] is start_frame
141+
elif (
142+
isinstance(annotation, TemporalClassificationQuestion)
143+
and annotation.value
144+
):
120145
if annotation.value[0].frames:
121-
frame_dict[annotation.value[0].frames[0][0]].append(annotation) # frames[0][0] is start_frame
146+
frame_dict[annotation.value[0].frames[0][0]].append(
147+
annotation
148+
) # frames[0][0] is start_frame
122149
return dict(frame_dict)
123150

124151
def add_url_to_masks(self, signer) -> "Label":

libs/labelbox/src/labelbox/data/annotation_types/temporal.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ class TemporalClassificationAnswer(BaseModel):
4747
description="List of (start_frame, end_frame) tuples in milliseconds",
4848
)
4949
classifications: Optional[
50-
List[Union["TemporalClassificationText", "TemporalClassificationQuestion"]]
50+
List[
51+
Union[
52+
"TemporalClassificationText", "TemporalClassificationQuestion"
53+
]
54+
]
5155
] = None
5256

5357

@@ -97,7 +101,11 @@ class TemporalClassificationText(BaseModel):
97101
description="List of (start_frame, end_frame, text_value) tuples",
98102
)
99103
classifications: Optional[
100-
List[Union["TemporalClassificationText", "TemporalClassificationQuestion"]]
104+
List[
105+
Union[
106+
"TemporalClassificationText", "TemporalClassificationQuestion"
107+
]
108+
]
101109
] = None
102110

103111

@@ -175,7 +183,11 @@ class TemporalClassificationQuestion(BaseModel):
175183
description="List of temporal answer options",
176184
)
177185
classifications: Optional[
178-
List[Union["TemporalClassificationText", "TemporalClassificationQuestion"]]
186+
List[
187+
Union[
188+
"TemporalClassificationText", "TemporalClassificationQuestion"
189+
]
190+
]
179191
] = None
180192

181193

libs/labelbox/src/labelbox/data/serialization/ndjson/label.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,10 @@ def _create_temporal_classifications(
175175
temporal_annotations = [
176176
annot
177177
for annot in label.annotations
178-
if isinstance(annot, (TemporalClassificationText, TemporalClassificationQuestion))
178+
if isinstance(
179+
annot,
180+
(TemporalClassificationText, TemporalClassificationQuestion),
181+
)
179182
]
180183

181184
if not temporal_annotations:

libs/labelbox/src/labelbox/data/serialization/ndjson/temporal.py

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ def create_temporal_ndjson_classifications(
6363
elif isinstance(first_ann, TemporalClassificationQuestion):
6464
answers = _process_question_group(group_anns, parent_frames=None)
6565
else:
66-
logger.warning(f"Unknown temporal annotation type: {type(first_ann)}")
66+
logger.warning(
67+
f"Unknown temporal annotation type: {type(first_ann)}"
68+
)
6769
continue
6870

6971
if answers: # Only add if we have valid answers
@@ -99,7 +101,9 @@ def _process_text_group(
99101
for ann in annotations:
100102
for start, end, text_value in ann.value:
101103
# Validate frames against parent if provided
102-
if parent_frames and not _is_frame_subset([(start, end)], parent_frames):
104+
if parent_frames and not _is_frame_subset(
105+
[(start, end)], parent_frames
106+
):
103107
logger.warning(
104108
f"Text value frames ({start}, {end}) not subset of parent frames {parent_frames}. Discarding."
105109
)
@@ -127,7 +131,9 @@ def _process_text_group(
127131

128132
# Assign nested classifications based on frame overlap
129133
if all_nested_classifications:
130-
parent_frame_tuples = [(f["start"], f["end"]) for f in unique_frames]
134+
parent_frame_tuples = [
135+
(f["start"], f["end"]) for f in unique_frames
136+
]
131137
# Filter nested classifications that overlap with this text value's frames
132138
relevant_nested = _filter_classifications_by_overlap(
133139
all_nested_classifications, parent_frame_tuples
@@ -138,7 +144,9 @@ def _process_text_group(
138144
assigned_nested.add(id(cls))
139145

140146
# Pass ONLY THIS text value's frames so nested answers are filtered correctly
141-
nested = _process_nested_classifications(relevant_nested, parent_frame_tuples)
147+
nested = _process_nested_classifications(
148+
relevant_nested, parent_frame_tuples
149+
)
142150
if nested:
143151
entry["classifications"] = nested
144152

@@ -151,7 +159,11 @@ def _process_text_group(
151159
if isinstance(cls, TemporalClassificationText):
152160
frames_info = cls.value[0][:2] if cls.value else "no frames"
153161
elif isinstance(cls, TemporalClassificationQuestion):
154-
frames_info = cls.value[0].frames if cls.value and cls.value[0].frames else "no frames"
162+
frames_info = (
163+
cls.value[0].frames
164+
if cls.value and cls.value[0].frames
165+
else "no frames"
166+
)
155167
else:
156168
frames_info = "unknown"
157169
logger.warning(
@@ -204,7 +216,9 @@ def _process_question_group(
204216

205217
# Collect nested classifications at answer level
206218
if answer.classifications:
207-
all_nested_by_answer[answer.name].extend(answer.classifications)
219+
all_nested_by_answer[answer.name].extend(
220+
answer.classifications
221+
)
208222

209223
# Track which nested classifications were assigned
210224
assigned_nested = set()
@@ -225,7 +239,9 @@ def _process_question_group(
225239

226240
# Assign nested classifications based on frame overlap
227241
if all_nested_by_answer[answer_name]:
228-
parent_frame_tuples = [(f["start"], f["end"]) for f in unique_frames]
242+
parent_frame_tuples = [
243+
(f["start"], f["end"]) for f in unique_frames
244+
]
229245
# Filter nested classifications that overlap with this answer's frames
230246
relevant_nested = _filter_classifications_by_overlap(
231247
all_nested_by_answer[answer_name], parent_frame_tuples
@@ -235,7 +251,9 @@ def _process_question_group(
235251
for cls in relevant_nested:
236252
assigned_nested.add(id(cls))
237253

238-
nested = _process_nested_classifications(relevant_nested, parent_frame_tuples)
254+
nested = _process_nested_classifications(
255+
relevant_nested, parent_frame_tuples
256+
)
239257
if nested:
240258
entry["classifications"] = nested
241259

@@ -248,7 +266,11 @@ def _process_question_group(
248266
if isinstance(cls, TemporalClassificationText):
249267
frames_info = cls.value[0][:2] if cls.value else "no frames"
250268
elif isinstance(cls, TemporalClassificationQuestion):
251-
frames_info = cls.value[0].frames if cls.value and cls.value[0].frames else "no frames"
269+
frames_info = (
270+
cls.value[0].frames
271+
if cls.value and cls.value[0].frames
272+
else "no frames"
273+
)
252274
else:
253275
frames_info = "unknown"
254276
logger.warning(
@@ -260,7 +282,9 @@ def _process_question_group(
260282

261283

262284
def _process_nested_classifications(
263-
classifications: List[Union[TemporalClassificationText, TemporalClassificationQuestion]],
285+
classifications: List[
286+
Union[TemporalClassificationText, TemporalClassificationQuestion]
287+
],
264288
parent_frames: List[Tuple[int, int]],
265289
) -> List[Dict[str, Any]]:
266290
"""
@@ -286,20 +310,26 @@ def _process_nested_classifications(
286310
elif isinstance(first_item, TemporalClassificationQuestion):
287311
answers = _process_question_group(group_items, parent_frames)
288312
else:
289-
logger.warning(f"Unknown nested classification type: {type(first_item)}")
313+
logger.warning(
314+
f"Unknown nested classification type: {type(first_item)}"
315+
)
290316
continue
291317

292318
if answers: # Only add if we have valid answers
293-
results.append({
294-
"name": display_name,
295-
"answer": answers,
296-
})
319+
results.append(
320+
{
321+
"name": display_name,
322+
"answer": answers,
323+
}
324+
)
297325

298326
return results
299327

300328

301329
def _filter_classifications_by_overlap(
302-
classifications: List[Union[TemporalClassificationText, TemporalClassificationQuestion]],
330+
classifications: List[
331+
Union[TemporalClassificationText, TemporalClassificationQuestion]
332+
],
303333
parent_frames: List[Tuple[int, int]],
304334
) -> List[Union[TemporalClassificationText, TemporalClassificationQuestion]]:
305335
"""

0 commit comments

Comments
 (0)