annofabcli 1.111.2__py3-none-any.whl → 1.112.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.
Files changed (184) hide show
  1. annofabcli/__main__.py +1 -2
  2. annofabcli/annotation/annotation_query.py +10 -10
  3. annofabcli/annotation/change_annotation_attributes.py +9 -9
  4. annofabcli/annotation/change_annotation_attributes_per_annotation.py +3 -4
  5. annofabcli/annotation/change_annotation_properties.py +13 -13
  6. annofabcli/annotation/copy_annotation.py +5 -5
  7. annofabcli/annotation/create_classification_annotation.py +6 -6
  8. annofabcli/annotation/delete_annotation.py +8 -8
  9. annofabcli/annotation/download_annotation_zip.py +1 -3
  10. annofabcli/annotation/dump_annotation.py +7 -7
  11. annofabcli/annotation/import_annotation.py +12 -12
  12. annofabcli/annotation/list_annotation.py +8 -8
  13. annofabcli/annotation/list_annotation_count.py +1 -2
  14. annofabcli/annotation/merge_segmentation.py +5 -5
  15. annofabcli/annotation/remove_segmentation_overlap.py +4 -4
  16. annofabcli/annotation/restore_annotation.py +6 -6
  17. annofabcli/annotation/subcommand_annotation.py +1 -2
  18. annofabcli/annotation_specs/add_attribute_restriction.py +4 -5
  19. annofabcli/annotation_specs/attribute_restriction.py +8 -8
  20. annofabcli/annotation_specs/export_annotation_specs.py +4 -5
  21. annofabcli/annotation_specs/get_annotation_specs_with_attribute_id_replaced.py +3 -4
  22. annofabcli/annotation_specs/get_annotation_specs_with_choice_id_replaced.py +3 -4
  23. annofabcli/annotation_specs/get_annotation_specs_with_label_id_replaced.py +3 -4
  24. annofabcli/annotation_specs/list_annotation_specs_attribute.py +9 -10
  25. annofabcli/annotation_specs/list_annotation_specs_choice.py +9 -10
  26. annofabcli/annotation_specs/list_annotation_specs_history.py +2 -2
  27. annofabcli/annotation_specs/list_annotation_specs_label.py +8 -9
  28. annofabcli/annotation_specs/list_annotation_specs_label_attribute.py +10 -11
  29. annofabcli/annotation_specs/list_attribute_restriction.py +2 -4
  30. annofabcli/annotation_specs/list_label_color.py +2 -3
  31. annofabcli/annotation_specs/put_label_color.py +3 -4
  32. annofabcli/annotation_specs/subcommand_annotation_specs.py +1 -3
  33. annofabcli/annotation_zip/list_annotation_3d_bounding_box.py +365 -0
  34. annofabcli/annotation_zip/list_annotation_bounding_box_2d.py +11 -12
  35. annofabcli/annotation_zip/list_range_annotation.py +24 -14
  36. annofabcli/annotation_zip/list_single_point_annotation.py +11 -12
  37. annofabcli/annotation_zip/subcommand_annotation_zip.py +3 -2
  38. annofabcli/annotation_zip/validate_annotation.py +8 -7
  39. annofabcli/comment/delete_comment.py +4 -6
  40. annofabcli/comment/download_comment_json.py +4 -6
  41. annofabcli/comment/list_all_comment.py +5 -6
  42. annofabcli/comment/list_comment.py +3 -4
  43. annofabcli/comment/put_comment.py +9 -10
  44. annofabcli/comment/put_comment_simply.py +5 -6
  45. annofabcli/comment/put_inspection_comment.py +1 -3
  46. annofabcli/comment/put_inspection_comment_simply.py +1 -3
  47. annofabcli/comment/put_onhold_comment.py +1 -3
  48. annofabcli/comment/put_onhold_comment_simply.py +1 -3
  49. annofabcli/comment/subcommand_comment.py +1 -3
  50. annofabcli/common/bokeh.py +4 -4
  51. annofabcli/common/cli.py +17 -17
  52. annofabcli/common/download.py +28 -29
  53. annofabcli/common/facade.py +37 -38
  54. annofabcli/common/image.py +14 -14
  55. annofabcli/common/utils.py +8 -8
  56. annofabcli/common/visualize.py +13 -13
  57. annofabcli/experimental/list_out_of_range_annotation_for_movie.py +3 -4
  58. annofabcli/experimental/subcommand_experimental.py +1 -3
  59. annofabcli/filesystem/draw_annotation.py +26 -26
  60. annofabcli/filesystem/filter_annotation.py +9 -10
  61. annofabcli/filesystem/mask_user_info.py +14 -14
  62. annofabcli/filesystem/merge_annotation.py +8 -8
  63. annofabcli/filesystem/subcommand_filesystem.py +1 -3
  64. annofabcli/input_data/copy_input_data.py +8 -9
  65. annofabcli/input_data/delete_input_data.py +2 -2
  66. annofabcli/input_data/delete_metadata_key_of_input_data.py +3 -5
  67. annofabcli/input_data/download_input_data_json.py +4 -6
  68. annofabcli/input_data/list_all_input_data.py +8 -8
  69. annofabcli/input_data/list_all_input_data_merged_task.py +4 -4
  70. annofabcli/input_data/list_input_data.py +4 -4
  71. annofabcli/input_data/put_input_data.py +5 -5
  72. annofabcli/input_data/put_input_data_with_zip.py +2 -3
  73. annofabcli/input_data/subcommand_input_data.py +1 -3
  74. annofabcli/input_data/update_input_data.py +6 -8
  75. annofabcli/input_data/update_metadata_of_input_data.py +3 -5
  76. annofabcli/instruction/copy_instruction.py +4 -5
  77. annofabcli/instruction/download_instruction.py +4 -5
  78. annofabcli/instruction/list_instruction_history.py +2 -2
  79. annofabcli/instruction/subcommand_instruction.py +1 -3
  80. annofabcli/instruction/upload_instruction.py +2 -3
  81. annofabcli/job/delete_job.py +1 -2
  82. annofabcli/job/list_job.py +4 -4
  83. annofabcli/job/list_last_job.py +3 -3
  84. annofabcli/job/subcommand_job.py +1 -3
  85. annofabcli/job/wait_job.py +4 -5
  86. annofabcli/my_account/get_my_account.py +1 -2
  87. annofabcli/my_account/subcommand_my_account.py +1 -3
  88. annofabcli/organization/list_organization.py +1 -2
  89. annofabcli/organization/subcommand_organization.py +1 -3
  90. annofabcli/organization_member/change_organization_member.py +3 -4
  91. annofabcli/organization_member/delete_organization_member.py +3 -4
  92. annofabcli/organization_member/invite_organization_member.py +1 -3
  93. annofabcli/organization_member/list_organization_member.py +2 -2
  94. annofabcli/organization_member/subcommand_organization_member.py +1 -3
  95. annofabcli/project/change_organization_of_project.py +3 -3
  96. annofabcli/project/change_project_status.py +3 -3
  97. annofabcli/project/copy_project.py +4 -4
  98. annofabcli/project/create_project.py +7 -7
  99. annofabcli/project/diff_projects.py +4 -5
  100. annofabcli/project/list_project.py +4 -4
  101. annofabcli/project/put_project.py +1 -2
  102. annofabcli/project/subcommand_project.py +1 -2
  103. annofabcli/project/update_configuration.py +3 -3
  104. annofabcli/project/update_project.py +6 -8
  105. annofabcli/project_member/change_project_members.py +7 -7
  106. annofabcli/project_member/copy_project_members.py +3 -3
  107. annofabcli/project_member/drop_project_members.py +1 -2
  108. annofabcli/project_member/invite_project_members.py +1 -3
  109. annofabcli/project_member/list_users.py +1 -2
  110. annofabcli/project_member/put_project_members.py +5 -5
  111. annofabcli/project_member/subcommand_project_member.py +1 -3
  112. annofabcli/stat_visualization/mask_visualization_dir.py +8 -9
  113. annofabcli/stat_visualization/merge_visualization_dir.py +6 -7
  114. annofabcli/stat_visualization/subcommand_stat_visualization.py +1 -2
  115. annofabcli/stat_visualization/summarize_whole_performance_csv.py +1 -2
  116. annofabcli/stat_visualization/write_graph.py +2 -3
  117. annofabcli/stat_visualization/write_performance_rating_csv.py +20 -27
  118. annofabcli/statistics/histogram.py +5 -6
  119. annofabcli/statistics/linegraph.py +13 -14
  120. annofabcli/statistics/list_annotation_area.py +38 -13
  121. annofabcli/statistics/list_annotation_attribute.py +9 -10
  122. annofabcli/statistics/list_annotation_attribute_filled_count.py +30 -31
  123. annofabcli/statistics/list_annotation_count.py +57 -58
  124. annofabcli/statistics/list_annotation_duration.py +33 -34
  125. annofabcli/statistics/list_video_duration.py +4 -5
  126. annofabcli/statistics/list_worktime.py +3 -3
  127. annofabcli/statistics/scatter.py +9 -8
  128. annofabcli/statistics/subcommand_statistics.py +1 -4
  129. annofabcli/statistics/summarize_task_count.py +4 -6
  130. annofabcli/statistics/summarize_task_count_by_task_id_group.py +2 -4
  131. annofabcli/statistics/summarize_task_count_by_user.py +1 -3
  132. annofabcli/statistics/visualization/dataframe/annotation_count.py +5 -4
  133. annofabcli/statistics/visualization/dataframe/annotation_duration.py +2 -3
  134. annofabcli/statistics/visualization/dataframe/cumulative_productivity.py +15 -17
  135. annofabcli/statistics/visualization/dataframe/productivity_per_date.py +17 -19
  136. annofabcli/statistics/visualization/dataframe/project_performance.py +3 -12
  137. annofabcli/statistics/visualization/dataframe/task.py +11 -12
  138. annofabcli/statistics/visualization/dataframe/task_worktime_by_phase_user.py +9 -10
  139. annofabcli/statistics/visualization/dataframe/user_performance.py +21 -19
  140. annofabcli/statistics/visualization/dataframe/whole_performance.py +3 -4
  141. annofabcli/statistics/visualization/dataframe/whole_productivity_per_date.py +12 -14
  142. annofabcli/statistics/visualization/dataframe/worktime_per_date.py +11 -13
  143. annofabcli/statistics/visualization/filtering_query.py +7 -7
  144. annofabcli/statistics/visualization/project_dir.py +27 -14
  145. annofabcli/statistics/visualize_annotation_count.py +22 -23
  146. annofabcli/statistics/visualize_annotation_duration.py +21 -22
  147. annofabcli/statistics/visualize_statistics.py +36 -33
  148. annofabcli/statistics/visualize_video_duration.py +18 -20
  149. annofabcli/supplementary/delete_supplementary_data.py +4 -4
  150. annofabcli/supplementary/list_supplementary_data.py +3 -3
  151. annofabcli/supplementary/put_supplementary_data.py +8 -8
  152. annofabcli/supplementary/subcommand_supplementary.py +1 -3
  153. annofabcli/task/cancel_acceptance.py +16 -17
  154. annofabcli/task/change_operator.py +10 -12
  155. annofabcli/task/change_status_to_break.py +7 -9
  156. annofabcli/task/change_status_to_on_hold.py +10 -12
  157. annofabcli/task/complete_tasks.py +17 -18
  158. annofabcli/task/copy_tasks.py +3 -5
  159. annofabcli/task/delete_metadata_key_of_task.py +4 -6
  160. annofabcli/task/delete_tasks.py +6 -6
  161. annofabcli/task/download_task_json.py +4 -6
  162. annofabcli/task/list_all_tasks.py +7 -7
  163. annofabcli/task/list_all_tasks_added_task_history.py +12 -12
  164. annofabcli/task/list_tasks.py +6 -6
  165. annofabcli/task/list_tasks_added_task_history.py +9 -9
  166. annofabcli/task/put_tasks.py +4 -5
  167. annofabcli/task/put_tasks_by_count.py +1 -2
  168. annofabcli/task/reject_tasks.py +18 -20
  169. annofabcli/task/subcommand_task.py +1 -3
  170. annofabcli/task/update_metadata_of_task.py +5 -6
  171. annofabcli/task_history/download_task_history_json.py +4 -6
  172. annofabcli/task_history/list_all_task_history.py +5 -6
  173. annofabcli/task_history/list_task_history.py +3 -4
  174. annofabcli/task_history/subcommand_task_history.py +1 -3
  175. annofabcli/task_history_event/download_task_history_event_json.py +4 -6
  176. annofabcli/task_history_event/list_all_task_history_event.py +6 -6
  177. annofabcli/task_history_event/list_worktime.py +15 -15
  178. annofabcli/task_history_event/subcommand_task_history_event.py +1 -2
  179. {annofabcli-1.111.2.dist-info → annofabcli-1.112.0.dist-info}/METADATA +9 -15
  180. annofabcli-1.112.0.dist-info/RECORD +229 -0
  181. {annofabcli-1.111.2.dist-info → annofabcli-1.112.0.dist-info}/WHEEL +1 -1
  182. annofabcli-1.111.2.dist-info/RECORD +0 -228
  183. {annofabcli-1.111.2.dist-info → annofabcli-1.112.0.dist-info}/entry_points.txt +0 -0
  184. {annofabcli-1.111.2.dist-info → annofabcli-1.112.0.dist-info}/licenses/LICENSE +0 -0
@@ -8,12 +8,10 @@ from __future__ import annotations
8
8
  import datetime
9
9
  import logging
10
10
  from pathlib import Path
11
- from typing import Any, Optional
11
+ from typing import Any
12
12
 
13
13
  import annofabapi
14
- import bokeh
15
14
  import bokeh.layouts
16
- import bokeh.palettes
17
15
  import pandas
18
16
  from bokeh.models.ui import UIElement
19
17
  from bokeh.plotting import ColumnDataSource
@@ -250,9 +248,9 @@ class WorktimePerDate:
250
248
  project_id: str,
251
249
  actual_worktime: ActualWorktime,
252
250
  *,
253
- task_history_event_json: Optional[Path] = None,
254
- start_date: Optional[str] = None,
255
- end_date: Optional[str] = None,
251
+ task_history_event_json: Path | None = None,
252
+ start_date: str | None = None,
253
+ end_date: str | None = None,
256
254
  ) -> WorktimePerDate:
257
255
  """
258
256
 
@@ -371,8 +369,8 @@ class WorktimePerDate:
371
369
  self,
372
370
  output_file: Path,
373
371
  *,
374
- target_user_id_list: Optional[list[str]] = None,
375
- metadata: Optional[dict[str, Any]] = None,
372
+ target_user_id_list: list[str] | None = None,
373
+ metadata: dict[str, Any] | None = None,
376
374
  ) -> None:
377
375
  """
378
376
  作業時間の累積値をプロットする。
@@ -468,7 +466,7 @@ class WorktimePerDate:
468
466
  username = df_subset.iloc[0]["username"]
469
467
 
470
468
  line_count += 1
471
- for line_graph, (x_column, y_column) in zip(line_graph_list, columns_list):
469
+ for line_graph, (x_column, y_column) in zip(line_graph_list, columns_list, strict=False):
472
470
  line_graph.add_line(
473
471
  source=source,
474
472
  x_column=x_column,
@@ -510,10 +508,10 @@ class WorktimePerDate:
510
508
 
511
509
  def mask_user_info(
512
510
  self,
513
- to_replace_for_user_id: Optional[dict[str, str]] = None,
514
- to_replace_for_username: Optional[dict[str, str]] = None,
515
- to_replace_for_account_id: Optional[dict[str, str]] = None,
516
- to_replace_for_biography: Optional[dict[str, str]] = None,
511
+ to_replace_for_user_id: dict[str, str] | None = None,
512
+ to_replace_for_username: dict[str, str] | None = None,
513
+ to_replace_for_account_id: dict[str, str] | None = None,
514
+ to_replace_for_biography: dict[str, str] | None = None,
517
515
  ) -> WorktimePerDate:
518
516
  """
519
517
  引数から渡された情報を元に、インスタンス変数`df`内のユーザー情報をマスクして、新しいインスタンスを返します。
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import logging
4
4
  from collections.abc import Collection
5
5
  from dataclasses import dataclass
6
- from typing import Any, Optional
6
+ from typing import Any
7
7
 
8
8
  from annofabapi.dataclass.task import Task as DcTask
9
9
  from annofabapi.models import Task
@@ -21,13 +21,13 @@ class FilteringQuery:
21
21
  絞り込み条件
22
22
  """
23
23
 
24
- task_query: Optional[TaskQuery] = None
25
- start_date: Optional[str] = None
26
- end_date: Optional[str] = None
27
- ignored_task_ids: Optional[Collection[str]] = None
24
+ task_query: TaskQuery | None = None
25
+ start_date: str | None = None
26
+ end_date: str | None = None
27
+ ignored_task_ids: Collection[str] | None = None
28
28
 
29
29
 
30
- def _get_first_annotation_started_datetime(sub_task_history_list: list[dict[str, Any]]) -> Optional[str]:
30
+ def _get_first_annotation_started_datetime(sub_task_history_list: list[dict[str, Any]]) -> str | None:
31
31
  """
32
32
  1個のタスクのタスク履歴一覧から、最初に教師付フェーズを作業した日時を取得します。
33
33
  """
@@ -40,7 +40,7 @@ def _get_first_annotation_started_datetime(sub_task_history_list: list[dict[str,
40
40
  return task_history_list_with_annotation_phase[0]["started_datetime"]
41
41
 
42
42
 
43
- def filter_task_histories(task_histories: dict[str, list[dict[str, Any]]], *, start_date: Optional[str] = None, end_date: Optional[str] = None) -> dict[str, list[dict[str, Any]]]:
43
+ def filter_task_histories(task_histories: dict[str, list[dict[str, Any]]], *, start_date: str | None = None, end_date: str | None = None) -> dict[str, list[dict[str, Any]]]:
44
44
  """
45
45
  タスク履歴を絞り込みます。
46
46
 
@@ -4,7 +4,7 @@ import json
4
4
  import logging
5
5
  from dataclasses import dataclass
6
6
  from pathlib import Path
7
- from typing import Any, Optional
7
+ from typing import Any
8
8
 
9
9
  from annofabapi.models import TaskPhase
10
10
  from dataclasses_json import DataClassJsonMixin
@@ -36,13 +36,9 @@ class ProjectDir(DataClassJsonMixin):
36
36
 
37
37
  Args:
38
38
  project_dir: ``annofabcli statistics visualize``コマンドによって出力されたプロジェクトディレクトリ
39
- metadata:
40
-
41
- タスクの完了条件(task_completion_criteria)は以下のいずれかです。
42
- - acceptance_completed: 受入フェーズの完了状態
43
- - acceptance_reached: 受入フェーズに到達
44
- - inspection_reached: 検査フェーズまたは受入フェーズに到達
45
- - annotation_started: 教師付フェーズが着手された
39
+ task_completion_criteria: タスクの完了条件
40
+ metadata: プロジェクトIDや絞り込み条件などの情報が含まれるメタデータ。この情報はグラフに埋め込まれます。
41
+ custom_production_volume_list: 独自の生産量に関する列情報のリスト
46
42
  """
47
43
 
48
44
  FILENAME_WHOLE_PERFORMANCE = "全体の生産性と品質.csv"
@@ -61,8 +57,8 @@ class ProjectDir(DataClassJsonMixin):
61
57
  project_dir: Path,
62
58
  task_completion_criteria: TaskCompletionCriteria,
63
59
  *,
64
- metadata: Optional[dict[str, Any]] = None,
65
- custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None,
60
+ metadata: dict[str, Any] | None = None,
61
+ custom_production_volume_list: list[ProductionVolumeColumn] | None = None,
66
62
  ) -> None:
67
63
  self.project_dir = project_dir
68
64
  self.task_completion_criteria = task_completion_criteria
@@ -130,7 +126,7 @@ class ProjectDir(DataClassJsonMixin):
130
126
  obj: AbstractPhaseCumulativeProductivity,
131
127
  phase: TaskPhase,
132
128
  *,
133
- user_id_list: Optional[list[str]] = None,
129
+ user_id_list: list[str] | None = None,
134
130
  minimal_output: bool = False,
135
131
  ) -> None:
136
132
  """
@@ -179,7 +175,7 @@ class ProjectDir(DataClassJsonMixin):
179
175
  phase_name = self.get_phase_name_for_filename(phase)
180
176
  obj.to_csv(self.project_dir / Path(f"{phase_name}者_{phase_name}開始日list.csv"))
181
177
 
182
- def write_performance_line_graph_per_date(self, obj: AbstractPhaseProductivityPerDate, phase: TaskPhase, *, user_id_list: Optional[list[str]] = None) -> None:
178
+ def write_performance_line_graph_per_date(self, obj: AbstractPhaseProductivityPerDate, phase: TaskPhase, *, user_id_list: list[str] | None = None) -> None:
183
179
  """
184
180
  指定したフェーズの開始日ごとの作業時間や生産性情報を、折れ線グラフとして出力します。
185
181
  """
@@ -396,7 +392,7 @@ class ProjectDir(DataClassJsonMixin):
396
392
  """`ユーザ_日付list-作業時間.csvを書き込む"""
397
393
  obj.to_csv(self.project_dir / self.FILENAME_WORKTIME_PER_DATE_USER)
398
394
 
399
- def write_worktime_line_graph(self, obj: WorktimePerDate, user_id_list: Optional[list[str]] = None) -> None:
395
+ def write_worktime_line_graph(self, obj: WorktimePerDate, user_id_list: list[str] | None = None) -> None:
400
396
  """横軸が日付、縦軸がユーザごとの作業時間である折れ線グラフを出力します。"""
401
397
  obj.plot_cumulatively(self.project_dir / "line-graph/累積折れ線-横軸_日-縦軸_作業時間.html", target_user_id_list=user_id_list, metadata=self.metadata)
402
398
 
@@ -429,7 +425,7 @@ class ProjectDir(DataClassJsonMixin):
429
425
  """
430
426
  print_json(obj.to_dict(encode_json=True), output=self.project_dir / self.FILENAME_MERGE_INFO, is_pretty=True)
431
427
 
432
- def read_metadata(self) -> Optional[dict[str, Any]]:
428
+ def read_metadata(self) -> dict[str, Any] | None:
433
429
  """
434
430
  `project_info`または`merge_info`の内容をメタデータとして読み込む。
435
431
  どちらも存在しない場合はNoneを返す。
@@ -448,6 +444,17 @@ class ProjectDir(DataClassJsonMixin):
448
444
 
449
445
  return None
450
446
 
447
+ def get_project_title(self) -> str:
448
+ """
449
+ `project_info`に記載されているプジェクトのタイトルを返します。
450
+ ただし`self.is_merged()`がTrueの場合は、`project_info`が存在しないので空文字を返します。
451
+ """
452
+ if self.is_merged():
453
+ return ""
454
+
455
+ project_info = self.read_project_info()
456
+ return project_info.project_title
457
+
451
458
 
452
459
  @dataclass
453
460
  class ProjectInfo(DataClassJsonMixin):
@@ -464,6 +471,12 @@ class ProjectInfo(DataClassJsonMixin):
464
471
  query: FilteringQuery
465
472
  """集計対象を絞り込むためのクエリ"""
466
473
 
474
+ production_volume_include_labels: list[str] | None = None
475
+ """生産量に含める「アノテーション仕様のラベル名(英語)」のリスト。Noneの場合、すべてのラベルを含む。"""
476
+
477
+ production_volume_exclude_labels: list[str] | None = None
478
+ """生産量から除外する「アノテーション仕様のラベル名(英語)」のリスト。Noneの場合、除外しない。"""
479
+
467
480
 
468
481
  @dataclass
469
482
  class MergingInfo(DataClassJsonMixin):
@@ -10,7 +10,7 @@ from collections import defaultdict
10
10
  from collections.abc import Collection, Sequence
11
11
  from functools import partial
12
12
  from pathlib import Path
13
- from typing import Any, Optional
13
+ from typing import Any
14
14
 
15
15
  import bokeh
16
16
  import numpy
@@ -20,7 +20,6 @@ from bokeh.models import LayoutDOM
20
20
  from bokeh.models.widgets.markups import Div
21
21
  from bokeh.plotting import figure
22
22
 
23
- import annofabcli
24
23
  import annofabcli.common.cli
25
24
  from annofabcli.common.bokeh import convert_1d_figure_list_to_2d, create_pretext_from_metadata
26
25
  from annofabcli.common.cli import (
@@ -56,11 +55,11 @@ def _get_y_axis_label(group_by: GroupBy) -> str:
56
55
  raise RuntimeError(f"group_by='{group_by}'が対象外です。")
57
56
 
58
57
 
59
- def convert_to_2d_figure_list(figures_dict: dict[tuple[str, str], list[figure]], *, ncols: int = 4) -> list[list[Optional[LayoutDOM]]]:
58
+ def convert_to_2d_figure_list(figures_dict: dict[tuple[str, str], list[figure]], *, ncols: int = 4) -> list[list[LayoutDOM | None]]:
60
59
  """
61
60
  grid layout用に2次元のfigureリストに変換する。
62
61
  """
63
- row_list: list[list[Optional[LayoutDOM]]] = []
62
+ row_list: list[list[LayoutDOM | None]] = []
64
63
 
65
64
  for (label_name, attribute_name), figure_list in figures_dict.items():
66
65
  row_list.append([Div(text=f"<h3>ラベル名='{label_name}', 属性名='{attribute_name}'</h3>")])
@@ -68,7 +67,7 @@ def convert_to_2d_figure_list(figures_dict: dict[tuple[str, str], list[figure]],
68
67
  for i in range(math.ceil(len(figure_list) / ncols)):
69
68
  start = i * ncols
70
69
  end = (i + 1) * ncols
71
- row: list[Optional[LayoutDOM]] = []
70
+ row: list[LayoutDOM | None] = []
72
71
  row.extend(figure_list[start:end])
73
72
  if len(row) < ncols:
74
73
  row.extend([None] * (ncols - len(row)))
@@ -101,11 +100,11 @@ def plot_label_histogram(
101
100
  group_by: GroupBy,
102
101
  output_file: Path,
103
102
  *,
104
- prior_keys: Optional[list[str]] = None,
105
- bin_width: Optional[int] = None,
103
+ prior_keys: list[str] | None = None,
104
+ bin_width: int | None = None,
106
105
  exclude_empty_value: bool = False,
107
106
  arrange_bin_edge: bool = False,
108
- metadata: Optional[dict[str, Any]] = None,
107
+ metadata: dict[str, Any] | None = None,
109
108
  ) -> None:
110
109
  """
111
110
  ラベルごとのアノテーション数のヒストグラムを出力する。
@@ -152,7 +151,7 @@ def plot_label_histogram(
152
151
 
153
152
  max_annotation_count = df.max(numeric_only=True).max()
154
153
 
155
- figure_list_2d: list[list[Optional[LayoutDOM]]] = [
154
+ figure_list_2d: list[list[LayoutDOM | None]] = [
156
155
  [
157
156
  Div(text="<h3>アノテーション数の分布(ラベル名ごと)</h3>"),
158
157
  ]
@@ -203,11 +202,11 @@ def plot_attribute_histogram( # noqa: PLR0915
203
202
  group_by: GroupBy,
204
203
  output_file: Path,
205
204
  *,
206
- prior_keys: Optional[list[AttributeValueKey]] = None,
207
- bin_width: Optional[int] = None,
205
+ prior_keys: list[AttributeValueKey] | None = None,
206
+ bin_width: int | None = None,
208
207
  exclude_empty_value: bool = False,
209
208
  arrange_bin_edge: bool = False,
210
- metadata: Optional[dict[str, Any]] = None,
209
+ metadata: dict[str, Any] | None = None,
211
210
  ) -> None:
212
211
  """
213
212
  属性値ごとのアノテーション数のヒストグラムを出力する。
@@ -256,7 +255,7 @@ def plot_attribute_histogram( # noqa: PLR0915
256
255
 
257
256
  max_annotation_count = df.max(numeric_only=True).max()
258
257
 
259
- figure_list_2d: list[list[Optional[LayoutDOM]]] = [
258
+ figure_list_2d: list[list[LayoutDOM | None]] = [
260
259
  [
261
260
  Div(text="<h3>アノテーション数の分布(属性値ごと)</h3>"),
262
261
  ]
@@ -322,10 +321,10 @@ class VisualizeAnnotationCount(CommandLine):
322
321
  annotation_path: Path,
323
322
  output_dir: Path,
324
323
  *,
325
- bin_width: Optional[int] = None,
326
- project_id: Optional[str] = None,
327
- target_task_ids: Optional[Collection[str]] = None,
328
- task_query: Optional[TaskQuery] = None,
324
+ bin_width: int | None = None,
325
+ project_id: str | None = None,
326
+ target_task_ids: Collection[str] | None = None,
327
+ task_query: TaskQuery | None = None,
329
328
  exclude_empty_value: bool = False,
330
329
  arrange_bin_edge: bool = False,
331
330
  ) -> None:
@@ -333,8 +332,8 @@ class VisualizeAnnotationCount(CommandLine):
333
332
  attributes_count_html = output_dir / "attributes_count.html"
334
333
 
335
334
  # 集計対象の属性を、選択肢系の属性にする
336
- annotation_specs: Optional[AnnotationSpecs] = None
337
- non_selective_attribute_name_keys: Optional[list[AttributeNameKey]] = None
335
+ annotation_specs: AnnotationSpecs | None = None
336
+ non_selective_attribute_name_keys: list[AttributeNameKey] | None = None
338
337
  if project_id is not None:
339
338
  annotation_specs = AnnotationSpecs(self.service, project_id)
340
339
  non_selective_attribute_name_keys = annotation_specs.non_selective_attribute_name_keys()
@@ -361,8 +360,8 @@ class VisualizeAnnotationCount(CommandLine):
361
360
  else:
362
361
  raise RuntimeError(f"group_by='{group_by}'が対象外です。")
363
362
 
364
- label_keys: Optional[list[str]] = None
365
- attribute_value_keys: Optional[list[AttributeValueKey]] = None
363
+ label_keys: list[str] | None = None
364
+ attribute_value_keys: list[AttributeValueKey] | None = None
366
365
  if annotation_specs is not None:
367
366
  label_keys = annotation_specs.label_keys()
368
367
  attribute_value_keys = annotation_specs.selective_attribute_value_keys()
@@ -406,7 +405,7 @@ class VisualizeAnnotationCount(CommandLine):
406
405
  if not self.validate(args):
407
406
  sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
408
407
 
409
- project_id: Optional[str] = args.project_id
408
+ project_id: str | None = args.project_id
410
409
  if project_id is not None:
411
410
  super().validate_project(project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
412
411
 
@@ -534,7 +533,7 @@ def main(args: argparse.Namespace) -> None:
534
533
  VisualizeAnnotationCount(service, facade, args).main()
535
534
 
536
535
 
537
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
536
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
538
537
  subcommand_name = "visualize_annotation_count"
539
538
  subcommand_help = "各ラベル、各属性値のアノテーション数をヒストグラムで可視化します。"
540
539
  description = "各ラベル、各属性値のアノテーション数をヒストグラムで可視化したファイルを出力します。"
@@ -9,7 +9,7 @@ from collections.abc import Collection, Sequence
9
9
  from enum import Enum
10
10
  from functools import partial
11
11
  from pathlib import Path
12
- from typing import Any, Optional
12
+ from typing import Any
13
13
 
14
14
  import bokeh
15
15
  import numpy
@@ -19,7 +19,6 @@ from bokeh.models import LayoutDOM
19
19
  from bokeh.models.widgets.markups import Div
20
20
  from bokeh.plotting import figure
21
21
 
22
- import annofabcli
23
22
  import annofabcli.common.cli
24
23
  from annofabcli.common.bokeh import convert_1d_figure_list_to_2d, create_pretext_from_metadata
25
24
  from annofabcli.common.cli import (
@@ -56,11 +55,11 @@ def plot_annotation_duration_histogram_by_label( # noqa: PLR0915
56
55
  output_file: Path,
57
56
  *,
58
57
  time_unit: TimeUnit,
59
- bin_width: Optional[float] = None,
60
- prior_keys: Optional[list[str]] = None,
58
+ bin_width: float | None = None,
59
+ prior_keys: list[str] | None = None,
61
60
  exclude_empty_value: bool = False,
62
61
  arrange_bin_edge: bool = False,
63
- metadata: Optional[dict[str, Any]] = None,
62
+ metadata: dict[str, Any] | None = None,
64
63
  ) -> None:
65
64
  """
66
65
  ラベルごとの区間アノテーションの長さのヒストグラムを出力します。
@@ -88,7 +87,7 @@ def plot_annotation_duration_histogram_by_label( # noqa: PLR0915
88
87
  df = df / 60
89
88
  return df
90
89
 
91
- def get_histogram_range(df: pandas.DataFrame) -> Optional[tuple[float, float]]:
90
+ def get_histogram_range(df: pandas.DataFrame) -> tuple[float, float] | None:
92
91
  if arrange_bin_edge:
93
92
  return (
94
93
  df.min(numeric_only=True).min(),
@@ -101,7 +100,7 @@ def plot_annotation_duration_histogram_by_label( # noqa: PLR0915
101
100
 
102
101
  max_duration = df.max(numeric_only=True).max()
103
102
 
104
- figure_list_2d: list[list[Optional[LayoutDOM]]] = [
103
+ figure_list_2d: list[list[LayoutDOM | None]] = [
105
104
  [
106
105
  Div(text="<h3>区間アノテーションの長さの分布(ラベル名ごと)</h3>"),
107
106
  ]
@@ -165,11 +164,11 @@ def plot_annotation_duration_histogram_by_attribute( # noqa: PLR0915
165
164
  output_file: Path,
166
165
  *,
167
166
  time_unit: TimeUnit,
168
- bin_width: Optional[float] = None,
169
- prior_keys: Optional[list[AttributeValueKey]] = None,
167
+ bin_width: float | None = None,
168
+ prior_keys: list[AttributeValueKey] | None = None,
170
169
  exclude_empty_value: bool = False,
171
170
  arrange_bin_edge: bool = False,
172
- metadata: Optional[dict[str, Any]] = None,
171
+ metadata: dict[str, Any] | None = None,
173
172
  ) -> None:
174
173
  """
175
174
  属性値ごとの区間アノテーションの長さのヒストグラムを出力します。
@@ -198,7 +197,7 @@ def plot_annotation_duration_histogram_by_attribute( # noqa: PLR0915
198
197
  df = df / 60
199
198
  return df
200
199
 
201
- def get_histogram_range(df: pandas.DataFrame) -> Optional[tuple[float, float]]:
200
+ def get_histogram_range(df: pandas.DataFrame) -> tuple[float, float] | None:
202
201
  if arrange_bin_edge:
203
202
  return (
204
203
  df.min(numeric_only=True).min(),
@@ -224,7 +223,7 @@ def plot_annotation_duration_histogram_by_attribute( # noqa: PLR0915
224
223
  max_duration = df.max(numeric_only=True).max()
225
224
  x_axis_label = "区間アノテーションの長さ[分]" if time_unit == TimeUnit.MINUTE else "区間アノテーションの長さ[秒]"
226
225
 
227
- figure_list_2d: list[list[Optional[LayoutDOM]]] = [
226
+ figure_list_2d: list[list[LayoutDOM | None]] = [
228
227
  [
229
228
  Div(text="<h3>区間アノテーションの長さの分布(属性値ごと)</h3>"),
230
229
  ]
@@ -290,10 +289,10 @@ class VisualizeAnnotationDuration(CommandLine):
290
289
  output_dir: Path,
291
290
  time_unit: TimeUnit,
292
291
  *,
293
- bin_width: Optional[int] = None,
294
- project_id: Optional[str] = None,
295
- target_task_ids: Optional[Collection[str]] = None,
296
- task_query: Optional[TaskQuery] = None,
292
+ bin_width: int | None = None,
293
+ project_id: str | None = None,
294
+ target_task_ids: Collection[str] | None = None,
295
+ task_query: TaskQuery | None = None,
297
296
  exclude_empty_value: bool = False,
298
297
  arrange_bin_edge: bool = False,
299
298
  ) -> None:
@@ -301,8 +300,8 @@ class VisualizeAnnotationDuration(CommandLine):
301
300
  duration_by_attribute_html = output_dir / "annotation_duration_by_attribute.html"
302
301
 
303
302
  # 集計対象の属性を、選択肢系の属性にする
304
- annotation_specs: Optional[AnnotationSpecs] = None
305
- non_selective_attribute_name_keys: Optional[list[AttributeNameKey]] = None
303
+ annotation_specs: AnnotationSpecs | None = None
304
+ non_selective_attribute_name_keys: list[AttributeNameKey] | None = None
306
305
  if project_id is not None:
307
306
  annotation_specs = AnnotationSpecs(self.service, project_id, annotation_type=DefaultAnnotationType.RANGE.value)
308
307
  non_selective_attribute_name_keys = annotation_specs.non_selective_attribute_name_keys()
@@ -315,8 +314,8 @@ class VisualizeAnnotationDuration(CommandLine):
315
314
  task_query=task_query,
316
315
  )
317
316
 
318
- label_keys: Optional[list[str]] = None
319
- attribute_value_keys: Optional[list[AttributeValueKey]] = None
317
+ label_keys: list[str] | None = None
318
+ attribute_value_keys: list[AttributeValueKey] | None = None
320
319
  if annotation_specs is not None:
321
320
  label_keys = annotation_specs.label_keys()
322
321
  attribute_value_keys = annotation_specs.selective_attribute_value_keys()
@@ -359,7 +358,7 @@ class VisualizeAnnotationDuration(CommandLine):
359
358
  if not self.validate(args):
360
359
  sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
361
360
 
362
- project_id: Optional[str] = args.project_id
361
+ project_id: str | None = args.project_id
363
362
  if project_id is not None:
364
363
  super().validate_project(project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
365
364
  project, _ = self.service.api.get_project(project_id)
@@ -487,7 +486,7 @@ def main(args: argparse.Namespace) -> None:
487
486
  VisualizeAnnotationDuration(service, facade, args).main()
488
487
 
489
488
 
490
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
489
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
491
490
  subcommand_name = "visualize_annotation_duration"
492
491
  subcommand_help = "ラベルごとまたは属性値ごとに区間アノテーションの長さをヒストグラムで可視化したファイルを出力します。"
493
492
  epilog = "オーナロールまたはアノテーションユーザロールを持つユーザで実行してください。"
@@ -6,9 +6,10 @@ import json
6
6
  import logging.handlers
7
7
  import sys
8
8
  import tempfile
9
+ from collections.abc import Callable
9
10
  from multiprocessing import Pool
10
11
  from pathlib import Path
11
- from typing import Any, Callable, Optional
12
+ from typing import Any
12
13
 
13
14
  import annofabapi
14
15
  import pandas
@@ -74,13 +75,13 @@ class WriteCsvGraph:
74
75
  project_dir: ProjectDir,
75
76
  actual_worktime: ActualWorktime,
76
77
  *,
77
- annotation_count: Optional[AnnotationCount] = None,
78
- input_data_count: Optional[InputDataCount] = None,
79
- custom_production_volume: Optional[CustomProductionVolume] = None,
78
+ annotation_count: AnnotationCount | None = None,
79
+ input_data_count: InputDataCount | None = None,
80
+ custom_production_volume: CustomProductionVolume | None = None,
80
81
  minimal_output: bool = False,
81
82
  output_only_text: bool = False,
82
- production_volume_include_labels: Optional[list[str]] = None,
83
- production_volume_exclude_labels: Optional[list[str]] = None,
83
+ production_volume_include_labels: list[str] | None = None,
84
+ production_volume_exclude_labels: list[str] | None = None,
84
85
  include_annotation_duration_seconds: bool = False,
85
86
  include_video_duration_minutes: bool = False,
86
87
  ) -> None:
@@ -101,9 +102,9 @@ class WriteCsvGraph:
101
102
  self.include_annotation_duration_seconds = include_annotation_duration_seconds
102
103
  self.include_video_duration_minutes = include_video_duration_minutes
103
104
 
104
- self.task: Optional[Task] = None
105
- self.worktime_per_date: Optional[WorktimePerDate] = None
106
- self.task_worktime_obj: Optional[TaskWorktimeByPhaseUser] = None
105
+ self.task: Task | None = None
106
+ self.worktime_per_date: WorktimePerDate | None = None
107
+ self.task_worktime_obj: TaskWorktimeByPhaseUser | None = None
107
108
 
108
109
  def _catch_exception(self, function: Callable[..., Any]) -> Callable[..., Any]:
109
110
  """
@@ -156,7 +157,7 @@ class WriteCsvGraph:
156
157
 
157
158
  return self.task
158
159
 
159
- def _prepare_custom_production_volume(self) -> Optional[CustomProductionVolume]:
160
+ def _prepare_custom_production_volume(self) -> CustomProductionVolume | None:
160
161
  """カスタム生産量の準備を行う"""
161
162
  custom_production_volume = self.custom_production_volume
162
163
 
@@ -170,7 +171,7 @@ class WriteCsvGraph:
170
171
 
171
172
  return custom_production_volume
172
173
 
173
- def _add_annotation_duration(self, custom_production_volume: Optional[CustomProductionVolume]) -> CustomProductionVolume:
174
+ def _add_annotation_duration(self, custom_production_volume: CustomProductionVolume | None) -> CustomProductionVolume:
174
175
  """区間アノテーションの長さを生産量に追加する"""
175
176
  logger.debug(f"project_id='{self.project_id}' :: 区間アノテーションの長さ('annotation_duration_minute')を計算します。")
176
177
  annotation_duration_obj = AnnotationDuration.from_annotation_zip(
@@ -198,7 +199,7 @@ class WriteCsvGraph:
198
199
  # CustomProductionVolumeが存在しない場合、新規作成
199
200
  return CustomProductionVolume(annotation_duration_obj.df, custom_production_volume_list=[annotation_duration_column])
200
201
 
201
- def _add_video_duration(self, custom_production_volume: Optional[CustomProductionVolume]) -> CustomProductionVolume:
202
+ def _add_video_duration(self, custom_production_volume: CustomProductionVolume | None) -> CustomProductionVolume:
202
203
  """動画の長さ(分)を生産量に追加する"""
203
204
  logger.debug(f"project_id='{self.project_id}' :: 動画の長さ('video_duration_minute')を計算します。")
204
205
  video_duration_by_task_id = self.visualize_source_files.get_video_duration_minutes_by_task_id()
@@ -297,7 +298,7 @@ class WriteCsvGraph:
297
298
  if not self.output_only_text:
298
299
  self.project_dir.write_user_performance_scatter_plot(user_performance)
299
300
 
300
- def write_cumulative_linegraph_by_user(self, user_id_list: Optional[list[str]] = None) -> None:
301
+ def write_cumulative_linegraph_by_user(self, user_id_list: list[str] | None = None) -> None:
301
302
  """ユーザごとの累積折れ線グラフをプロットする。"""
302
303
  task_worktime_obj = self._get_task_worktime_obj()
303
304
  annotator_obj = AnnotatorCumulativeProductivity.from_df_wrapper(task_worktime_obj)
@@ -309,7 +310,7 @@ class WriteCsvGraph:
309
310
  self.project_dir.write_cumulative_line_graph(inspector_obj, phase=TaskPhase.INSPECTION, user_id_list=user_id_list, minimal_output=self.minimal_output)
310
311
  self.project_dir.write_cumulative_line_graph(acceptor_obj, phase=TaskPhase.ACCEPTANCE, user_id_list=user_id_list, minimal_output=self.minimal_output)
311
312
 
312
- def write_worktime_per_date(self, user_id_list: Optional[list[str]] = None) -> None:
313
+ def write_worktime_per_date(self, user_id_list: list[str] | None = None) -> None:
313
314
  """日ごとの作業時間情報を出力する。"""
314
315
  worktime_per_date_obj = self._get_worktime_per_date()
315
316
 
@@ -328,7 +329,7 @@ class WriteCsvGraph:
328
329
  self.project_dir.write_whole_productivity_line_graph_per_date(productivity_per_completed_date_obj)
329
330
  self.project_dir.write_whole_productivity_line_graph_per_annotation_started_date(productivity_per_started_date_obj)
330
331
 
331
- def write_user_productivity_per_date(self, user_id_list: Optional[list[str]] = None) -> None:
332
+ def write_user_productivity_per_date(self, user_id_list: list[str] | None = None) -> None:
332
333
  """ユーザごとの日ごとの生産性情報を出力する。"""
333
334
  task_worktime_obj = self._get_task_worktime_obj()
334
335
 
@@ -362,14 +363,14 @@ class VisualizingStatisticsMain:
362
363
  # その他
363
364
  download_latest: bool = False,
364
365
  is_get_task_histories_one_of_each: bool = False,
365
- actual_worktime: Optional[ActualWorktime] = None,
366
- annotation_count: Optional[AnnotationCount] = None,
367
- input_data_count: Optional[InputDataCount] = None,
368
- custom_production_volume: Optional[CustomProductionVolume] = None,
369
- user_ids: Optional[list[str]] = None,
366
+ actual_worktime: ActualWorktime | None = None,
367
+ annotation_count: AnnotationCount | None = None,
368
+ input_data_count: InputDataCount | None = None,
369
+ custom_production_volume: CustomProductionVolume | None = None,
370
+ user_ids: list[str] | None = None,
370
371
  not_download_visualization_source_files: bool = False,
371
- production_volume_include_labels: Optional[list[str]] = None,
372
- production_volume_exclude_labels: Optional[list[str]] = None,
372
+ production_volume_include_labels: list[str] | None = None,
373
+ production_volume_exclude_labels: list[str] | None = None,
373
374
  ) -> None:
374
375
  self.service = service
375
376
  self.facade = AnnofabApiFacade(service)
@@ -400,6 +401,8 @@ class VisualizingStatisticsMain:
400
401
  measurement_datetime=annofabapi.utils.str_now(),
401
402
  task_completion_criteria=self.task_completion_criteria,
402
403
  query=self.filtering_query,
404
+ production_volume_include_labels=self.production_volume_include_labels,
405
+ production_volume_exclude_labels=self.production_volume_exclude_labels,
403
406
  )
404
407
  return project_summary
405
408
 
@@ -501,7 +504,7 @@ class VisualizingStatisticsMain:
501
504
  self,
502
505
  project_id: str,
503
506
  root_output_dir: Path,
504
- ) -> Optional[Path]:
507
+ ) -> Path | None:
505
508
  try:
506
509
  output_project_dir = root_output_dir / project_id
507
510
  self.visualize_statistics(
@@ -518,7 +521,7 @@ class VisualizingStatisticsMain:
518
521
  project_id_list: list[str],
519
522
  root_output_dir: Path,
520
523
  *,
521
- parallelism: Optional[int] = None,
524
+ parallelism: int | None = None,
522
525
  ) -> list[Path]:
523
526
  output_project_dir_list: list[Path] = []
524
527
 
@@ -581,11 +584,11 @@ class VisualizeStatistics(CommandLine):
581
584
  temp_dir: Path,
582
585
  filtering_query: FilteringQuery,
583
586
  task_completion_criteria: TaskCompletionCriteria,
584
- user_id_list: Optional[list[str]],
587
+ user_id_list: list[str] | None,
585
588
  actual_worktime: ActualWorktime,
586
- annotation_count: Optional[AnnotationCount],
587
- input_data_count: Optional[InputDataCount],
588
- custom_production_volume: Optional[CustomProductionVolume],
589
+ annotation_count: AnnotationCount | None,
590
+ input_data_count: InputDataCount | None,
591
+ custom_production_volume: CustomProductionVolume | None,
589
592
  download_latest: bool, # noqa: FBT001
590
593
  is_get_task_histories_one_of_each: bool, # noqa: FBT001
591
594
  minimal_output: bool, # noqa: FBT001
@@ -593,9 +596,9 @@ class VisualizeStatistics(CommandLine):
593
596
  not_download_visualization_source_files: bool, # noqa: FBT001
594
597
  project_id_list: list[str],
595
598
  root_output_dir: Path,
596
- parallelism: Optional[int],
597
- production_volume_include_labels: Optional[list[str]] = None,
598
- production_volume_exclude_labels: Optional[list[str]] = None,
599
+ parallelism: int | None,
600
+ production_volume_include_labels: list[str] | None = None,
601
+ production_volume_exclude_labels: list[str] | None = None,
599
602
  ) -> None:
600
603
  main_obj = VisualizingStatisticsMain(
601
604
  service=self.service,
@@ -650,7 +653,7 @@ class VisualizeStatistics(CommandLine):
650
653
  task_completion_criteria = TaskCompletionCriteria(args.task_completion_criteria)
651
654
 
652
655
  dict_task_query = annofabcli.common.cli.get_json_from_args(args.task_query)
653
- task_query: Optional[TaskQuery] = None
656
+ task_query: TaskQuery | None = None
654
657
  if dict_task_query is not None:
655
658
  task_query = TaskQuery.from_dict(dict_task_query)
656
659
  logger.warning("引数 '--task_query' は非推奨です。代わりに '--task_completion_criteria' を指定してください。")
@@ -906,7 +909,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
906
909
  parser.set_defaults(subcommand_func=main)
907
910
 
908
911
 
909
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
912
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
910
913
  subcommand_name = "visualize"
911
914
  subcommand_help = "生産性に関するCSVファイルやグラフを出力します。"
912
915
  description = "生産性に関するCSVファイルやグラフを出力します。"