annofabcli 1.98.0__py3-none-any.whl → 1.99.0__py3-none-any.whl

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.
@@ -20,7 +20,7 @@ from typing import Any, Optional, Union
20
20
 
21
21
  import annofabapi
22
22
  import pandas
23
- from annofabapi.models import AdditionalDataDefinitionType, ProjectMemberRole, TaskPhase, TaskStatus
23
+ from annofabapi.models import ProjectMemberRole, TaskPhase, TaskStatus
24
24
  from annofabapi.parser import (
25
25
  SimpleAnnotationParser,
26
26
  SimpleAnnotationParserByTask,
@@ -29,6 +29,7 @@ from annofabapi.parser import (
29
29
  lazy_parse_simple_annotation_zip,
30
30
  lazy_parse_simple_annotation_zip_by_task,
31
31
  )
32
+ from annofabapi.pydantic_models.additional_data_definition_type import AdditionalDataDefinitionType
32
33
  from dataclasses_json import DataClassJsonMixin, config
33
34
 
34
35
  import annofabcli
@@ -115,18 +116,18 @@ class AnnotationCounter(abc.ABC):
115
116
  @dataclass(frozen=True)
116
117
  class AnnotationCounterByTask(AnnotationCounter, DataClassJsonMixin):
117
118
  task_id: str
118
- status: TaskStatus
119
- phase: TaskPhase
120
- phase_stage: int
119
+ task_status: TaskStatus
120
+ task_phase: TaskPhase
121
+ task_phase_stage: int
121
122
  input_data_count: int
122
123
 
123
124
 
124
125
  @dataclass(frozen=True)
125
126
  class AnnotationCounterByInputData(AnnotationCounter, DataClassJsonMixin):
126
127
  task_id: str
127
- status: TaskStatus
128
- phase: TaskPhase
129
- phase_stage: int
128
+ task_status: TaskStatus
129
+ task_phase: TaskPhase
130
+ task_phase_stage: int
130
131
 
131
132
  input_data_id: str
132
133
  input_data_name: str
@@ -258,9 +259,9 @@ class ListAnnotationCounterByInputData:
258
259
 
259
260
  return AnnotationCounterByInputData(
260
261
  task_id=simple_annotation["task_id"],
261
- phase=TaskPhase(simple_annotation["task_phase"]),
262
- phase_stage=simple_annotation["task_phase_stage"],
263
- status=TaskStatus(simple_annotation["task_status"]),
262
+ task_phase=TaskPhase(simple_annotation["task_phase"]),
263
+ task_phase_stage=simple_annotation["task_phase_stage"],
264
+ task_status=TaskStatus(simple_annotation["task_status"]),
264
265
  input_data_id=simple_annotation["input_data_id"],
265
266
  input_data_name=simple_annotation["input_data_name"],
266
267
  annotation_count=sum(annotation_count_by_label.values()),
@@ -355,9 +356,9 @@ class ListAnnotationCounterByTask:
355
356
 
356
357
  return AnnotationCounterByTask(
357
358
  task_id=last_simple_annotation["task_id"],
358
- status=TaskStatus(last_simple_annotation["task_status"]),
359
- phase=TaskPhase(last_simple_annotation["task_phase"]),
360
- phase_stage=last_simple_annotation["task_phase_stage"],
359
+ task_status=TaskStatus(last_simple_annotation["task_status"]),
360
+ task_phase=TaskPhase(last_simple_annotation["task_phase"]),
361
+ task_phase_stage=last_simple_annotation["task_phase_stage"],
361
362
  input_data_count=input_data_count,
362
363
  annotation_count=sum(annotation_count_by_label.values()),
363
364
  annotation_count_by_label=annotation_count_by_label,
@@ -483,9 +484,9 @@ class AttributeCountCsv:
483
484
  def get_columns() -> list[AttributeValueKey]:
484
485
  basic_columns = [
485
486
  ("task_id", "", ""),
486
- ("status", "", ""),
487
- ("phase", "", ""),
488
- ("phase_stage", "", ""),
487
+ ("task_status", "", ""),
488
+ ("task_phase", "", ""),
489
+ ("task_phase_stage", "", ""),
489
490
  ("input_data_count", "", ""),
490
491
  ("annotation_count", "", ""),
491
492
  ]
@@ -495,9 +496,9 @@ class AttributeCountCsv:
495
496
  def to_cell(c: AnnotationCounterByTask) -> dict[AttributeValueKey, Any]:
496
497
  cell = {
497
498
  ("task_id", "", ""): c.task_id,
498
- ("status", "", ""): c.status.value,
499
- ("phase", "", ""): c.phase.value,
500
- ("phase_stage", "", ""): c.phase_stage,
499
+ ("task_status", "", ""): c.task_status.value,
500
+ ("task_phase", "", ""): c.task_phase.value,
501
+ ("task_phase_stage", "", ""): c.task_phase_stage,
501
502
  ("input_data_count", "", ""): c.input_data_count,
502
503
  ("annotation_count", "", ""): c.annotation_count,
503
504
  }
@@ -521,9 +522,9 @@ class AttributeCountCsv:
521
522
  def get_columns() -> list[AttributeValueKey]:
522
523
  basic_columns = [
523
524
  ("task_id", "", ""),
524
- ("status", "", ""),
525
- ("phase", "", ""),
526
- ("phase_stage", "", ""),
525
+ ("task_status", "", ""),
526
+ ("task_phase", "", ""),
527
+ ("task_phase_stage", "", ""),
527
528
  ("input_data_id", "", ""),
528
529
  ("input_data_name", "", ""),
529
530
  ("frame_no", "", ""),
@@ -538,9 +539,9 @@ class AttributeCountCsv:
538
539
  ("input_data_name", "", ""): c.input_data_name,
539
540
  ("frame_no", "", ""): c.frame_no,
540
541
  ("task_id", "", ""): c.task_id,
541
- ("status", "", ""): c.status.value,
542
- ("phase", "", ""): c.phase.value,
543
- ("phase_stage", "", ""): c.phase_stage,
542
+ ("task_status", "", ""): c.task_status.value,
543
+ ("task_phase", "", ""): c.task_phase.value,
544
+ ("task_phase_stage", "", ""): c.task_phase_stage,
544
545
  ("annotation_count", "", ""): c.annotation_count,
545
546
  }
546
547
  cell.update(c.annotation_count_by_attribute)
@@ -587,9 +588,9 @@ class LabelCountCsv:
587
588
  def get_columns() -> list[str]:
588
589
  basic_columns = [
589
590
  "task_id",
590
- "status",
591
- "phase",
592
- "phase_stage",
591
+ "task_status",
592
+ "task_phase",
593
+ "task_phase_stage",
593
594
  "input_data_count",
594
595
  "annotation_count",
595
596
  ]
@@ -599,9 +600,9 @@ class LabelCountCsv:
599
600
  def to_dict(c: AnnotationCounterByTask) -> dict[str, Any]:
600
601
  d = {
601
602
  "task_id": c.task_id,
602
- "status": c.status.value,
603
- "phase": c.phase.value,
604
- "phase_stage": c.phase_stage,
603
+ "task_status": c.task_status.value,
604
+ "task_phase": c.task_phase.value,
605
+ "task_phase_stage": c.task_phase_stage,
605
606
  "input_data_count": c.input_data_count,
606
607
  "annotation_count": c.annotation_count,
607
608
  }
@@ -625,9 +626,9 @@ class LabelCountCsv:
625
626
  def get_columns() -> list[str]:
626
627
  basic_columns = [
627
628
  "task_id",
628
- "status",
629
- "phase",
630
- "phase_stage",
629
+ "task_status",
630
+ "task_phase",
631
+ "task_phase_stage",
631
632
  "input_data_id",
632
633
  "input_data_name",
633
634
  "frame_no",
@@ -642,9 +643,9 @@ class LabelCountCsv:
642
643
  "input_data_name": c.input_data_name,
643
644
  "frame_no": c.frame_no,
644
645
  "task_id": c.task_id,
645
- "status": c.status.value,
646
- "phase": c.phase.value,
647
- "phase_stage": c.phase_stage,
646
+ "task_status": c.task_status.value,
647
+ "task_phase": c.task_phase.value,
648
+ "task_phase_stage": c.task_phase_stage,
648
649
  "annotation_count": c.annotation_count,
649
650
  }
650
651
  d.update(c.annotation_count_by_label)
@@ -697,6 +698,48 @@ class AnnotationSpecs:
697
698
  )
698
699
  return result
699
700
 
701
+ def attribute_name_keys(
702
+ self,
703
+ excluded_attribute_types: Optional[Collection[AdditionalDataDefinitionType]] = None,
704
+ include_attribute_types: Optional[Collection[AdditionalDataDefinitionType]] = None,
705
+ ) -> list[tuple[str, str]]:
706
+ """
707
+ 属性名の一覧を取得します。
708
+
709
+ Args:
710
+ include_attribute_types: 指定した属性の種類に合致した属性名の一覧を取得します。
711
+ excluded_attribute_types: 指定した属性の種類に合致していない属性名の一覧を取得します。
712
+
713
+ Raise:
714
+ ValueError: `include_attribute_types`と`excluded_attribute_types`の両方が指定された場合に発生します。
715
+ """
716
+ if excluded_attribute_types is not None and include_attribute_types is not None:
717
+ raise ValueError("`include_attribute_types`と`excluded_attribute_types`の両方が指定されています。")
718
+
719
+ result = []
720
+ for label in self._labels_v1:
721
+ label_name_en = AddProps.get_message(label["label_name"], MessageLocale.EN)
722
+ assert label_name_en is not None
723
+
724
+ for attribute in label["additional_data_definitions"]:
725
+ if excluded_attribute_types is not None and AdditionalDataDefinitionType(attribute["type"]) in excluded_attribute_types:
726
+ continue
727
+
728
+ if include_attribute_types is not None and AdditionalDataDefinitionType(attribute["type"]) not in include_attribute_types:
729
+ continue
730
+
731
+ attribute_name_en = AddProps.get_message(attribute["name"], MessageLocale.EN)
732
+ assert attribute_name_en is not None
733
+ result.append((label_name_en, attribute_name_en))
734
+
735
+ duplicated_attribute_names = [key for key, value in collections.Counter(result).items() if value > 1]
736
+ if len(duplicated_attribute_names) > 0:
737
+ logger.warning(
738
+ f"アノテーション仕様の属性情報(ラベル英語名、属性英語名)が重複しています。アノテーション個数が正しく算出できない可能性があります。:: {duplicated_attribute_names}" # noqa: E501
739
+ )
740
+
741
+ return result
742
+
700
743
  def selective_attribute_value_keys(self) -> list[AttributeValueKey]:
701
744
  """
702
745
  選択系の属性の属性値のキーの一覧。
@@ -109,9 +109,9 @@ class AnnotationDuration(DataClassJsonMixin):
109
109
  """
110
110
 
111
111
  task_id: str
112
- status: TaskStatus
113
- phase: TaskPhase
114
- phase_stage: int
112
+ task_status: TaskStatus
113
+ task_phase: TaskPhase
114
+ task_phase_stage: int
115
115
 
116
116
  input_data_id: str
117
117
  input_data_name: str
@@ -239,9 +239,9 @@ class ListAnnotationDurationByInputData:
239
239
 
240
240
  return AnnotationDuration(
241
241
  task_id=simple_annotation["task_id"],
242
- phase=TaskPhase(simple_annotation["task_phase"]),
243
- phase_stage=simple_annotation["task_phase_stage"],
244
- status=TaskStatus(simple_annotation["task_status"]),
242
+ task_phase=TaskPhase(simple_annotation["task_phase"]),
243
+ task_phase_stage=simple_annotation["task_phase_stage"],
244
+ task_status=TaskStatus(simple_annotation["task_status"]),
245
245
  input_data_id=simple_annotation["input_data_id"],
246
246
  input_data_name=simple_annotation["input_data_name"],
247
247
  video_duration_second=video_duration_second,
@@ -375,9 +375,9 @@ class AnnotationDurationCsvByAttribute:
375
375
  ) -> list[AttributeValueKey]:
376
376
  basic_columns = [
377
377
  ("task_id", "", ""),
378
- ("status", "", ""),
379
- ("phase", "", ""),
380
- ("phase_stage", "", ""),
378
+ ("task_status", "", ""),
379
+ ("task_phase", "", ""),
380
+ ("task_phase_stage", "", ""),
381
381
  ("input_data_id", "", ""),
382
382
  ("input_data_name", "", ""),
383
383
  ("video_duration_second", "", ""),
@@ -396,9 +396,9 @@ class AnnotationDurationCsvByAttribute:
396
396
  ("input_data_id", "", ""): c.input_data_id,
397
397
  ("input_data_name", "", ""): c.input_data_name,
398
398
  ("task_id", "", ""): c.task_id,
399
- ("status", "", ""): c.status.value,
400
- ("phase", "", ""): c.phase.value,
401
- ("phase_stage", "", ""): c.phase_stage,
399
+ ("task_status", "", ""): c.task_status.value,
400
+ ("task_phase", "", ""): c.task_phase.value,
401
+ ("task_phase_stage", "", ""): c.task_phase_stage,
402
402
  ("video_duration_second", "", ""): c.video_duration_second,
403
403
  ("annotation_duration_second", "", ""): c.annotation_duration_second,
404
404
  }
@@ -438,9 +438,9 @@ class AnnotationDurationCsvByLabel:
438
438
  ) -> list[str]:
439
439
  basic_columns = [
440
440
  "task_id",
441
- "status",
442
- "phase",
443
- "phase_stage",
441
+ "task_status",
442
+ "task_phase",
443
+ "task_phase_stage",
444
444
  "input_data_id",
445
445
  "input_data_name",
446
446
  "video_duration_second",
@@ -459,9 +459,9 @@ class AnnotationDurationCsvByLabel:
459
459
  "input_data_id": c.input_data_id,
460
460
  "input_data_name": c.input_data_name,
461
461
  "task_id": c.task_id,
462
- "status": c.status.value,
463
- "phase": c.phase.value,
464
- "phase_stage": c.phase_stage,
462
+ "task_status": c.task_status.value,
463
+ "task_phase": c.task_phase.value,
464
+ "task_phase_stage": c.task_phase_stage,
465
465
  "video_duration_second": c.video_duration_second,
466
466
  "annotation_duration_second": c.annotation_duration_second,
467
467
  }
@@ -5,6 +5,7 @@ import annofabcli
5
5
  import annofabcli.common.cli
6
6
  import annofabcli.stat_visualization.merge_visualization_dir
7
7
  import annofabcli.statistics.list_annotation_attribute
8
+ import annofabcli.statistics.list_annotation_attribute_filled_count
8
9
  import annofabcli.statistics.list_annotation_count
9
10
  import annofabcli.statistics.list_annotation_duration
10
11
  import annofabcli.statistics.list_video_duration
@@ -23,8 +24,10 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
23
24
 
24
25
  # サブコマンドの定義
25
26
  annofabcli.statistics.list_annotation_attribute.add_parser(subparsers)
27
+ annofabcli.statistics.list_annotation_attribute_filled_count.add_parser(subparsers)
26
28
  annofabcli.statistics.list_annotation_count.add_parser(subparsers)
27
29
  annofabcli.statistics.list_annotation_duration.add_parser(subparsers)
30
+
28
31
  annofabcli.statistics.list_video_duration.add_parser(subparsers)
29
32
  annofabcli.statistics.list_worktime.add_parser(subparsers)
30
33
  annofabcli.statistics.summarize_task_count.add_parser(subparsers)