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
@@ -1,11 +1,11 @@
1
1
  import json
2
2
  import logging
3
- import logging.config
4
3
  import os
5
4
  import re
6
5
  import sys
6
+ from collections.abc import Callable
7
7
  from pathlib import Path
8
- from typing import Any, Callable, Optional, TypeVar, Union
8
+ from typing import Any, TypeVar
9
9
 
10
10
  import dateutil.parser
11
11
  import isodate
@@ -46,7 +46,7 @@ def duplicated_set(target_list: list[T]) -> set[T]:
46
46
  return {x for x in set(target_list) if target_list.count(x) > 1}
47
47
 
48
48
 
49
- def output_string(target: str, output: Optional[Union[str, Path]] = None) -> None:
49
+ def output_string(target: str, output: str | Path | None = None) -> None:
50
50
  """
51
51
  文字列を出力する。
52
52
 
@@ -64,7 +64,7 @@ def output_string(target: str, output: Optional[Union[str, Path]] = None) -> Non
64
64
  logger.info(f"'{output}'を出力しました。")
65
65
 
66
66
 
67
- def print_json(target: Any, is_pretty: bool = False, output: Optional[Union[str, Path]] = None) -> None: # noqa: ANN401, FBT001, FBT002
67
+ def print_json(target: Any, is_pretty: bool = False, output: str | Path | None = None) -> None: # noqa: ANN401, FBT001, FBT002
68
68
  """
69
69
  JSONを出力する。
70
70
 
@@ -80,7 +80,7 @@ def print_json(target: Any, is_pretty: bool = False, output: Optional[Union[str,
80
80
  output_string(json.dumps(target, ensure_ascii=False), output)
81
81
 
82
82
 
83
- def print_csv(df: pandas.DataFrame, output: Optional[Union[str, Path]] = None, to_csv_kwargs: Optional[dict[str, Any]] = None) -> None:
83
+ def print_csv(df: pandas.DataFrame, output: str | Path | None = None, to_csv_kwargs: dict[str, Any] | None = None) -> None:
84
84
  if output is not None:
85
85
  Path(output).parent.mkdir(parents=True, exist_ok=True)
86
86
 
@@ -98,7 +98,7 @@ def print_csv(df: pandas.DataFrame, output: Optional[Union[str, Path]] = None, t
98
98
  logger.info(f"'{output}'を出力しました。")
99
99
 
100
100
 
101
- def print_id_list(id_list: list[Any], output: Optional[Union[str, Path]]) -> None:
101
+ def print_id_list(id_list: list[Any], output: str | Path | None) -> None:
102
102
  s = "\n".join(id_list)
103
103
  output_string(s, output)
104
104
 
@@ -106,7 +106,7 @@ def print_id_list(id_list: list[Any], output: Optional[Union[str, Path]]) -> Non
106
106
  def print_according_to_format(
107
107
  target: Any, # noqa: ANN401
108
108
  format: FormatArgument, # noqa: A002
109
- output: Optional[Union[str, Path]] = None,
109
+ output: str | Path | None = None,
110
110
  ) -> None:
111
111
  """
112
112
  コマンドライン引数 ``--format`` の値にしたがって、内容を出力する。
@@ -171,7 +171,7 @@ def is_file_scheme(str_value: str) -> bool:
171
171
  return str_value.startswith("file://")
172
172
 
173
173
 
174
- def get_file_scheme_path(str_value: str) -> Optional[str]:
174
+ def get_file_scheme_path(str_value: str) -> str | None:
175
175
  """
176
176
  file schemaのパスを取得する。file schemeでない場合は、Noneを返す
177
177
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import enum
4
- from typing import Any, Optional
4
+ from typing import Any
5
5
 
6
6
  import annofabapi
7
7
  import more_itertools
@@ -32,15 +32,15 @@ class AddProps:
32
32
  """
33
33
 
34
34
  #: 組織メンバ一覧のキャッシュ
35
- _organization_members: Optional[list[OrganizationMember]] = None
36
- _project_member_list: Optional[list[ProjectMember]] = None
35
+ _organization_members: list[OrganizationMember] | None = None
36
+ _project_member_list: list[ProjectMember] | None = None
37
37
 
38
38
  def __init__(self, service: annofabapi.Resource, project_id: str) -> None:
39
39
  self.service = service
40
40
  self.project_id = project_id
41
41
 
42
- self._specs_labels: Optional[list[dict[str, Any]]] = None
43
- self._specs_inspection_phrases: Optional[list[dict[str, Any]]] = None
42
+ self._specs_labels: list[dict[str, Any]] | None = None
43
+ self._specs_inspection_phrases: list[dict[str, Any]] | None = None
44
44
 
45
45
  def _set_annotation_specs(self): # noqa: ANN202
46
46
  """
@@ -84,7 +84,7 @@ class AddProps:
84
84
  return millisecond / 1000 / 3600
85
85
 
86
86
  @staticmethod
87
- def get_message(i18n_messages: dict[str, Any], locale: MessageLocale) -> Optional[str]:
87
+ def get_message(i18n_messages: dict[str, Any], locale: MessageLocale) -> str | None:
88
88
  messages: list[dict[str, Any]] = i18n_messages["messages"]
89
89
  dict_message = more_itertools.first_true(messages, pred=lambda e: e["lang"] == locale.value)
90
90
  if dict_message is not None:
@@ -112,7 +112,7 @@ class AddProps:
112
112
  target["username"] = username
113
113
  return target
114
114
 
115
- def get_project_member_from_account_id(self, account_id: str) -> Optional[ProjectMember]:
115
+ def get_project_member_from_account_id(self, account_id: str) -> ProjectMember | None:
116
116
  if self._project_member_list is None:
117
117
  project_member_list = self.service.wrapper.get_all_project_members(self.project_id, query_params={"include_inactive_member": True})
118
118
  self._project_member_list = project_member_list
@@ -128,22 +128,22 @@ class AddProps:
128
128
  organization, _ = self.service.api.get_organization_of_project(project_id)
129
129
  return organization["organization_name"]
130
130
 
131
- def get_phrase_name(self, phrase_id: str, locale: MessageLocale) -> Optional[str]:
132
- phrase: Optional[dict[str, Any]] = more_itertools.first_true(self.specs_inspection_phrases, pred=lambda e: e["id"] == phrase_id)
131
+ def get_phrase_name(self, phrase_id: str, locale: MessageLocale) -> str | None:
132
+ phrase: dict[str, Any] | None = more_itertools.first_true(self.specs_inspection_phrases, pred=lambda e: e["id"] == phrase_id)
133
133
  if phrase is None:
134
134
  return None
135
135
 
136
136
  return self.get_message(phrase["text"], locale)
137
137
 
138
- def get_label_name(self, label_id: str, locale: MessageLocale) -> Optional[str]:
138
+ def get_label_name(self, label_id: str, locale: MessageLocale) -> str | None:
139
139
  label = more_itertools.first_true(self.specs_labels, pred=lambda e: e["label_id"] == label_id)
140
140
  if label is None:
141
141
  return None
142
142
 
143
143
  return self.get_message(label["label_name"], locale)
144
144
 
145
- def get_additional_data_name(self, additional_data_definition_id: str, locale: MessageLocale, label_id: Optional[str] = None) -> Optional[str]:
146
- def _get_additional_data_name(arg_additional_data_definitions: list[dict[str, Any]]) -> Optional[str]:
145
+ def get_additional_data_name(self, additional_data_definition_id: str, locale: MessageLocale, label_id: str | None = None) -> str | None:
146
+ def _get_additional_data_name(arg_additional_data_definitions: list[dict[str, Any]]) -> str | None:
147
147
  additional_data = more_itertools.first_true(
148
148
  arg_additional_data_definitions,
149
149
  pred=lambda e: e["additional_data_definition_id"] == additional_data_definition_id,
@@ -194,7 +194,7 @@ class AddProps:
194
194
  """
195
195
  return self._add_user_info(instruction_history)
196
196
 
197
- def add_properties_to_inspection(self, inspection: Inspection, detail: Optional[dict[str, Any]] = None) -> Inspection:
197
+ def add_properties_to_inspection(self, inspection: Inspection, detail: dict[str, Any] | None = None) -> Inspection:
198
198
  """
199
199
  検査コメントに、以下のキーを追加する.
200
200
  commenter_user_id
@@ -4,13 +4,12 @@ import json
4
4
  import logging
5
5
  import zipfile
6
6
  from pathlib import Path
7
- from typing import Any, Optional
7
+ from typing import Any
8
8
 
9
9
  import annofabapi
10
10
  import pandas
11
11
  from annofabapi.parser import SimpleAnnotationZipParser
12
12
 
13
- import annofabcli
14
13
  import annofabcli.common.cli
15
14
  from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login
16
15
  from annofabcli.common.download import DownloadingFile
@@ -59,7 +58,7 @@ class ListOutOfRangeAnnotationForMovieMain:
59
58
  project_id: str,
60
59
  task_list: list[dict[str, Any]],
61
60
  input_data_list: list[dict[str, Any]],
62
- annotation_zip: Optional[Path],
61
+ annotation_zip: Path | None,
63
62
  ) -> pandas.DataFrame:
64
63
  if annotation_zip is None:
65
64
  logger.info(f"{len(task_list)} 件のアノテーション情報をWebAPIで取得します。")
@@ -123,7 +122,7 @@ class ListOutOfRangeAnnotationForMovieMain:
123
122
  def list_out_of_range_annotation_for_movie(
124
123
  self,
125
124
  project_id: str,
126
- task_id_list: Optional[list[str]],
125
+ task_id_list: list[str] | None,
127
126
  parse_annotation_zip: bool = False, # noqa: FBT001, FBT002
128
127
  ) -> pandas.DataFrame:
129
128
  cache_dir = annofabcli.common.utils.get_cache_dir()
@@ -1,7 +1,5 @@
1
1
  import argparse
2
- from typing import Optional
3
2
 
4
- import annofabcli
5
3
  import annofabcli.common.cli
6
4
  from annofabcli.experimental import list_out_of_range_annotation_for_movie
7
5
 
@@ -13,7 +11,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
13
11
  list_out_of_range_annotation_for_movie.add_parser(subparsers)
14
12
 
15
13
 
16
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
14
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
17
15
  subcommand_name = "experimental"
18
16
  subcommand_help = "アルファ版のサブコマンド"
19
17
  description = "アルファ版のサブコマンド。予告なしに削除されたり、コマンドライン引数が変わったりします。"
@@ -4,10 +4,10 @@ import argparse
4
4
  import json
5
5
  import logging
6
6
  import sys
7
- from collections.abc import Collection, Iterator
7
+ from collections.abc import Callable, Collection, Iterator
8
8
  from dataclasses import dataclass
9
9
  from pathlib import Path
10
- from typing import Any, Callable, Optional, Union
10
+ from typing import Any
11
11
 
12
12
  import pandas
13
13
  from annofabapi.parser import SimpleAnnotationParser, lazy_parse_simple_annotation_dir, lazy_parse_simple_annotation_zip
@@ -27,7 +27,7 @@ from annofabcli.common.facade import TaskQuery, match_annotation_with_task_query
27
27
  logger = logging.getLogger(__name__)
28
28
 
29
29
 
30
- Color = Union[str, tuple[int, int, int]]
30
+ Color = str | tuple[int, int, int]
31
31
  IsParserFunc = Callable[[SimpleAnnotationParser], bool]
32
32
 
33
33
 
@@ -59,10 +59,10 @@ class DrawingAnnotationForOneImage:
59
59
 
60
60
  def __init__(
61
61
  self,
62
- label_color_dict: Optional[dict[str, Color]] = None,
63
- target_label_names: Optional[Collection[str]] = None,
64
- polyline_labels: Optional[Collection[str]] = None,
65
- drawing_options: Optional[DrawingOptions] = None,
62
+ label_color_dict: dict[str, Color] | None = None,
63
+ target_label_names: Collection[str] | None = None,
64
+ polyline_labels: Collection[str] | None = None,
65
+ drawing_options: DrawingOptions | None = None,
66
66
  ) -> None:
67
67
  self.label_color_dict = label_color_dict if label_color_dict is not None else {}
68
68
  self.target_label_names = set(target_label_names) if target_label_names is not None else None
@@ -161,9 +161,9 @@ class DrawingAnnotationForOneImage:
161
161
  def main( # noqa: ANN201
162
162
  self,
163
163
  parser: SimpleAnnotationParser,
164
- image_file: Optional[Path],
164
+ image_file: Path | None,
165
165
  output_file: Path,
166
- image_size: Optional[tuple[int, int]] = None,
166
+ image_size: tuple[int, int] | None = None,
167
167
  ):
168
168
  """画像にアノテーションを描画したファイルを出力する。
169
169
 
@@ -190,9 +190,9 @@ class DrawingAnnotationForOneImage:
190
190
 
191
191
 
192
192
  def create_is_target_parser_func(
193
- task_ids: Optional[Collection[str]] = None,
194
- task_query: Optional[TaskQuery] = None,
195
- ) -> Optional[IsParserFunc]:
193
+ task_ids: Collection[str] | None = None,
194
+ task_query: TaskQuery | None = None,
195
+ ) -> IsParserFunc | None:
196
196
  if task_ids is None and task_query is None:
197
197
  return None
198
198
 
@@ -215,17 +215,17 @@ def create_is_target_parser_func(
215
215
 
216
216
  def draw_annotation_all( # noqa: ANN201, PLR0913
217
217
  iter_parser: Iterator[SimpleAnnotationParser],
218
- image_dir: Optional[Path],
219
- input_data_id_relation_dict: Optional[dict[str, str]],
218
+ image_dir: Path | None,
219
+ input_data_id_relation_dict: dict[str, str] | None,
220
220
  output_dir: Path,
221
221
  *,
222
- target_task_ids: Optional[Collection[str]] = None,
223
- task_query: Optional[TaskQuery] = None,
224
- label_color_dict: Optional[dict[str, Color]] = None,
225
- target_label_names: Optional[Collection[str]] = None,
226
- polyline_labels: Optional[Collection[str]] = None,
227
- drawing_options: Optional[DrawingOptions] = None,
228
- default_image_size: Optional[tuple[int, int]] = None,
222
+ target_task_ids: Collection[str] | None = None,
223
+ task_query: TaskQuery | None = None,
224
+ label_color_dict: dict[str, Color] | None = None,
225
+ target_label_names: Collection[str] | None = None,
226
+ polyline_labels: Collection[str] | None = None,
227
+ drawing_options: DrawingOptions | None = None,
228
+ default_image_size: tuple[int, int] | None = None,
229
229
  ):
230
230
  drawing = DrawingAnnotationForOneImage(
231
231
  label_color_dict=label_color_dict,
@@ -251,7 +251,7 @@ def draw_annotation_all( # noqa: ANN201, PLR0913
251
251
  logger.warning(f"input_data_id='{input_data_id}'に対応する画像ファイルのパスが見つかりませんでした。")
252
252
  continue
253
253
 
254
- image_file: Optional[Path] = None
254
+ image_file: Path | None = None
255
255
  if image_dir is not None and input_data_id_relation_dict is not None:
256
256
  image_file = image_dir / input_data_id_relation_dict[input_data_id]
257
257
  if not image_file.exists():
@@ -291,7 +291,7 @@ class DrawAnnotation(CommandLineWithoutWebapi):
291
291
  def main(self) -> None:
292
292
  args = self.args
293
293
 
294
- default_image_size: Optional[tuple[int, int]] = None
294
+ default_image_size: tuple[int, int] | None = None
295
295
  if args.default_image_size is not None:
296
296
  default_image_size = annofabcli.common.cli.get_input_data_size(args.default_image_size)
297
297
  if default_image_size is None:
@@ -322,7 +322,7 @@ class DrawAnnotation(CommandLineWithoutWebapi):
322
322
  else:
323
323
  iter_parser = lazy_parse_simple_annotation_dir(annotation_path)
324
324
 
325
- input_data_id_relation_dict: Optional[dict[str, str]] = None
325
+ input_data_id_relation_dict: dict[str, str] | None = None
326
326
  if args.input_data_id_csv is not None:
327
327
  df = pandas.read_csv(
328
328
  args.input_data_id_csv,
@@ -330,7 +330,7 @@ class DrawAnnotation(CommandLineWithoutWebapi):
330
330
  header=None,
331
331
  names=("input_data_id", "image_path"),
332
332
  )
333
- input_data_id_relation_dict = dict(zip(df["input_data_id"], df["image_path"]))
333
+ input_data_id_relation_dict = dict(zip(df["input_data_id"], df["image_path"], strict=False))
334
334
 
335
335
  task_query = TaskQuery.from_dict(annofabcli.common.cli.get_json_from_args(args.task_query)) if args.task_query is not None else None
336
336
 
@@ -439,7 +439,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
439
439
  parser.set_defaults(subcommand_func=main)
440
440
 
441
441
 
442
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
442
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
443
443
  subcommand_name = "draw_annotation"
444
444
 
445
445
  subcommand_help = "画像にアノテーションを描画します。"
@@ -7,11 +7,10 @@ import zipfile
7
7
  from collections import defaultdict
8
8
  from dataclasses import dataclass
9
9
  from pathlib import Path
10
- from typing import Any, Optional
10
+ from typing import Any
11
11
 
12
12
  from annofabapi.parser import lazy_parse_simple_annotation_dir, lazy_parse_simple_annotation_zip
13
13
 
14
- import annofabcli
15
14
  import annofabcli.common.cli
16
15
  from annofabcli.common.cli import COMMAND_LINE_ERROR_STATUS_CODE
17
16
  from annofabcli.common.facade import TaskQuery, match_annotation_with_task_query
@@ -21,13 +20,13 @@ logger = logging.getLogger(__name__)
21
20
 
22
21
  @dataclass
23
22
  class FilterQuery:
24
- task_query: Optional[TaskQuery] = None
25
- task_id_set: Optional[set[str]] = None
26
- exclude_task_id_set: Optional[set[str]] = None
27
- input_data_id_set: Optional[set[str]] = None
28
- exclude_input_data_id_set: Optional[set[str]] = None
29
- input_data_name_set: Optional[set[str]] = None
30
- exclude_input_data_name_set: Optional[set[str]] = None
23
+ task_query: TaskQuery | None = None
24
+ task_id_set: set[str] | None = None
25
+ exclude_task_id_set: set[str] | None = None
26
+ input_data_id_set: set[str] | None = None
27
+ exclude_input_data_id_set: set[str] | None = None
28
+ input_data_name_set: set[str] | None = None
29
+ exclude_input_data_name_set: set[str] | None = None
31
30
 
32
31
 
33
32
  def match_query( # pylint: disable=too-many-return-statements # noqa: PLR0911
@@ -220,7 +219,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
220
219
  parser.set_defaults(subcommand_func=main)
221
220
 
222
221
 
223
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
222
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
224
223
  subcommand_name = "filter_annotation"
225
224
 
226
225
  subcommand_help = "アノテーションzipから特定のファイルを絞り込んで、zip展開します。"
@@ -2,7 +2,7 @@ import argparse
2
2
  import logging
3
3
  from functools import partial
4
4
  from pathlib import Path
5
- from typing import Any, Optional, Union
5
+ from typing import Any
6
6
 
7
7
  import numpy
8
8
  import pandas
@@ -98,7 +98,7 @@ def create_masked_name(name: str) -> str:
98
98
  return _num2alpha(hash_value)
99
99
 
100
100
 
101
- def get_replaced_user_id_set_from_biography(df: pandas.DataFrame, not_masked_location_set: Optional[set[str]] = None) -> set[str]:
101
+ def get_replaced_user_id_set_from_biography(df: pandas.DataFrame, not_masked_location_set: set[str] | None = None) -> set[str]:
102
102
  if not_masked_location_set is None:
103
103
  filtered_df = df
104
104
  else:
@@ -115,7 +115,7 @@ def _get_header_row_count(df: pandas.DataFrame) -> int:
115
115
  return 1
116
116
 
117
117
 
118
- def _get_tuple_column(df: pandas.DataFrame, column: str) -> Union[str, tuple]:
118
+ def _get_tuple_column(df: pandas.DataFrame, column: str) -> str | tuple:
119
119
  """
120
120
  列名を返します。ヘッダ行が複数行の場合は、タプルで返します。
121
121
 
@@ -136,8 +136,8 @@ def _get_tuple_column(df: pandas.DataFrame, column: str) -> Union[str, tuple]:
136
136
  def replace_by_columns( # noqa: ANN201
137
137
  df: pandas.DataFrame,
138
138
  replacement_dict: dict[str, str],
139
- main_column: Union[str, tuple],
140
- sub_columns: Optional[list[Any]] = None,
139
+ main_column: str | tuple,
140
+ sub_columns: list[Any] | None = None,
141
141
  ):
142
142
  """引数dfの中のユーザ情報を、指定した列名を元に置換します。
143
143
 
@@ -148,7 +148,7 @@ def replace_by_columns( # noqa: ANN201
148
148
  sub_column: main_columnと同じ値で置換する列(ex: username)
149
149
  """
150
150
 
151
- def _get_username(row: pandas.Series, main_column: Union[str, tuple], sub_column: Union[str, tuple]) -> str:
151
+ def _get_username(row: pandas.Series, main_column: str | tuple, sub_column: str | tuple) -> str:
152
152
  if row[main_column] in replacement_dict:
153
153
  return replacement_dict[row[main_column]]
154
154
  else:
@@ -196,7 +196,7 @@ def get_masked_account_id(df: pandas.DataFrame, replace_dict_by_user_id: dict[st
196
196
  return df.apply(_get_account_id, axis=1)
197
197
 
198
198
 
199
- def get_replaced_biography_set(df: pandas.DataFrame, not_masked_location_set: Optional[set[str]] = None) -> set[str]:
199
+ def get_replaced_biography_set(df: pandas.DataFrame, not_masked_location_set: set[str] | None = None) -> set[str]:
200
200
  biography_set = set(df["biography"].dropna())
201
201
 
202
202
  if not_masked_location_set is None:
@@ -209,8 +209,8 @@ def get_replaced_biography_set(df: pandas.DataFrame, not_masked_location_set: Op
209
209
 
210
210
  def create_replacement_dict_by_user_id(
211
211
  df: pandas.DataFrame,
212
- not_masked_biography_set: Optional[set[str]] = None,
213
- not_masked_user_id_set: Optional[set[str]] = None,
212
+ not_masked_biography_set: set[str] | None = None,
213
+ not_masked_user_id_set: set[str] | None = None,
214
214
  ) -> dict[str, str]:
215
215
  """
216
216
  keyが置換対象のuser_id、valueが置換後のマスクされたuser_idであるdictを作成する。
@@ -227,7 +227,7 @@ def create_replacement_dict_by_user_id(
227
227
 
228
228
  def create_replacement_dict_by_biography(
229
229
  df: pandas.DataFrame,
230
- not_masked_biography_set: Optional[set[str]] = None,
230
+ not_masked_biography_set: set[str] | None = None,
231
231
  ) -> dict[str, str]:
232
232
  """
233
233
  keyが置換対象のbiography、valueが置換後のマスクされた biography であるdictを作成する。
@@ -270,7 +270,7 @@ def replace_biography(df: pandas.DataFrame, replacement_dict_by_user_id: dict[st
270
270
  user_id_column = _get_tuple_column(df, "user_id")
271
271
  biography_column = _get_tuple_column(df, "biography")
272
272
 
273
- def _get_biography(row: pandas.Series, user_id_column: Union[str, tuple], biography_column: Union[str, tuple]) -> str:
273
+ def _get_biography(row: pandas.Series, user_id_column: str | tuple, biography_column: str | tuple) -> str:
274
274
  if row[user_id_column] in replacement_dict_by_user_id:
275
275
  # マスク対象のユーザなら biographyをマスクする
276
276
  biography = row[biography_column]
@@ -288,8 +288,8 @@ def replace_biography(df: pandas.DataFrame, replacement_dict_by_user_id: dict[st
288
288
  def create_masked_user_info_df(
289
289
  df: pandas.DataFrame,
290
290
  *,
291
- not_masked_biography_set: Optional[set[str]] = None,
292
- not_masked_user_id_set: Optional[set[str]] = None,
291
+ not_masked_biography_set: set[str] | None = None,
292
+ not_masked_user_id_set: set[str] | None = None,
293
293
  ) -> pandas.DataFrame:
294
294
  if "user_id" not in df:
295
295
  logger.warning("引数`df`に`user_id`列が存在しないため、ユーザ情報をマスクできません。")
@@ -360,7 +360,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
360
360
  parser.set_defaults(subcommand_func=main)
361
361
 
362
362
 
363
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
363
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
364
364
  subcommand_name = "mask_user_info"
365
365
  subcommand_help = "CSVに記載されたユーザ情報をマスクします。"
366
366
  description = "CSVに記載されたユーザ情報をマスクします。CSVの`user_id`,`username`,`biography`,`account_id` 列をマスクします。"
@@ -3,9 +3,9 @@ import json
3
3
  import logging
4
4
  import sys
5
5
  import zipfile
6
- from collections.abc import Collection, Iterator
6
+ from collections.abc import Callable, Collection, Iterator
7
7
  from pathlib import Path
8
- from typing import Any, Callable, Optional
8
+ from typing import Any
9
9
 
10
10
  from annofabapi.parser import (
11
11
  SimpleAnnotationDirParser,
@@ -110,7 +110,7 @@ class MergeAnnotationMain:
110
110
  json.dump(simple_annotation, f, ensure_ascii=False)
111
111
 
112
112
  @staticmethod
113
- def _get_parser(annotation_path: Path, zip_file: Optional[zipfile.ZipFile], json_path: Path) -> Optional[SimpleAnnotationParser]:
113
+ def _get_parser(annotation_path: Path, zip_file: zipfile.ZipFile | None, json_path: Path) -> SimpleAnnotationParser | None:
114
114
  if annotation_path.is_dir():
115
115
  if (annotation_path / json_path).exists():
116
116
  return SimpleAnnotationDirParser(annotation_path / json_path)
@@ -126,8 +126,8 @@ class MergeAnnotationMain:
126
126
 
127
127
  @staticmethod
128
128
  def create_is_target_parser_func(
129
- task_ids: Optional[Collection[str]] = None,
130
- ) -> Optional[IsParserFunc]:
129
+ task_ids: Collection[str] | None = None,
130
+ ) -> IsParserFunc | None:
131
131
  if task_ids is None:
132
132
  return None
133
133
 
@@ -147,13 +147,13 @@ class MergeAnnotationMain:
147
147
  annotation_path1: Path,
148
148
  annotation_path2: Path,
149
149
  output_dir: Path,
150
- target_task_ids: Optional[Collection[str]] = None,
150
+ target_task_ids: Collection[str] | None = None,
151
151
  ):
152
152
  is_target_parser_func = self.create_is_target_parser_func(target_task_ids)
153
153
 
154
154
  iter_parser1 = self.create_iter_parser(annotation_path1)
155
155
 
156
- zip_file2: Optional[zipfile.ZipFile] = None
156
+ zip_file2: zipfile.ZipFile | None = None
157
157
  if annotation_path2.is_file():
158
158
  zip_file2 = zipfile.ZipFile(str(annotation_path2), "r") # pylint: disable=consider-using-with
159
159
 
@@ -244,7 +244,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
244
244
  parser.set_defaults(subcommand_func=main)
245
245
 
246
246
 
247
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
247
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
248
248
  subcommand_name = "merge_annotation"
249
249
 
250
250
  subcommand_help = "2つのアノテーションzip(またはzipを展開したディレクトリ)をマージします。"
@@ -1,7 +1,5 @@
1
1
  import argparse
2
- from typing import Optional
3
2
 
4
- import annofabcli
5
3
  import annofabcli.common.cli
6
4
  import annofabcli.filesystem.draw_annotation
7
5
  import annofabcli.filesystem.filter_annotation
@@ -19,7 +17,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
19
17
  annofabcli.filesystem.merge_annotation.add_parser(subparsers)
20
18
 
21
19
 
22
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
20
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
23
21
  subcommand_name = "filesystem"
24
22
  subcommand_help = "ファイル操作関係(Web APIにアクセスしない)のサブコマンド"
25
23
  description = "ファイル操作関係(Web APIにアクセスしない)のサブコマンド"
@@ -7,13 +7,12 @@ import multiprocessing
7
7
  import sys
8
8
  import tempfile
9
9
  from pathlib import Path
10
- from typing import Any, Optional
10
+ from typing import Any
11
11
 
12
12
  import annofabapi
13
13
  import more_itertools
14
14
  from annofabapi.models import ProjectMemberRole
15
15
 
16
- import annofabcli
17
16
  import annofabcli.common.cli
18
17
  from annofabcli.common.cli import (
19
18
  COMMAND_LINE_ERROR_STATUS_CODE,
@@ -49,7 +48,7 @@ class CopyInputDataMain(CommandLineWithConfirm):
49
48
 
50
49
  CommandLineWithConfirm.__init__(self, all_yes)
51
50
 
52
- def copy_supplementary_data(self, src_supplementary_data: dict[str, Any], last_updated_datetime: Optional[str]) -> dict[str, Any]:
51
+ def copy_supplementary_data(self, src_supplementary_data: dict[str, Any], last_updated_datetime: str | None) -> dict[str, Any]:
53
52
  request_body = {
54
53
  "supplementary_data_name": src_supplementary_data["supplementary_data_name"],
55
54
  "supplementary_data_path": src_supplementary_data["supplementary_data_path"],
@@ -70,7 +69,7 @@ class CopyInputDataMain(CommandLineWithConfirm):
70
69
  src_supplementary_data_list: list[dict[str, Any]],
71
70
  dest_supplementary_data_list: list[dict[str, Any]],
72
71
  *,
73
- logging_prefix: Optional[str] = None,
72
+ logging_prefix: str | None = None,
74
73
  ) -> None:
75
74
  for src_supplementary_data in src_supplementary_data_list:
76
75
  dest_supplementary_data = more_itertools.first_true(
@@ -93,7 +92,7 @@ class CopyInputDataMain(CommandLineWithConfirm):
93
92
  f"src_project_id='{self.src_project_id}', dest_project_id='{self.dest_project_id}'"
94
93
  )
95
94
 
96
- def copy_input_data(self, src_input_data: dict[str, Any], last_updated_datetime: Optional[str]) -> dict[str, Any]:
95
+ def copy_input_data(self, src_input_data: dict[str, Any], last_updated_datetime: str | None) -> dict[str, Any]:
97
96
  request_body = {
98
97
  "input_data_name": src_input_data["input_data_name"],
99
98
  "input_data_path": src_input_data["input_data_path"],
@@ -108,7 +107,7 @@ class CopyInputDataMain(CommandLineWithConfirm):
108
107
  self,
109
108
  input_data_id: str,
110
109
  *,
111
- input_data_index: Optional[int] = None,
110
+ input_data_index: int | None = None,
112
111
  ) -> bool:
113
112
  def get_confirm_message(supplementary_data_count: int, *, exists_in_dest_project: bool) -> str:
114
113
  message = f"入力データ(input_data_id='{input_data_id}')と補助情報{supplementary_data_count}件をコピーしますか?"
@@ -181,9 +180,9 @@ class CopyInputDataMain(CommandLineWithConfirm):
181
180
 
182
181
  def copy_input_data_list(
183
182
  self,
184
- input_data_id_list: Optional[list[str]],
183
+ input_data_id_list: list[str] | None,
185
184
  *,
186
- parallelism: Optional[int] = None,
185
+ parallelism: int | None = None,
187
186
  ) -> None:
188
187
  if input_data_id_list is None:
189
188
  input_data_id_list = self.get_all_input_data_id_list(self.src_project_id)
@@ -298,7 +297,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
298
297
  parser.set_defaults(subcommand_func=main)
299
298
 
300
299
 
301
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
300
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
302
301
  subcommand_name = "copy"
303
302
  subcommand_help = "入力データと関連する補助情報を別プロジェクトにコピーします。"
304
303
  description = (
@@ -1,6 +1,6 @@
1
1
  import argparse
2
2
  import logging
3
- from typing import Any, Optional
3
+ from typing import Any
4
4
 
5
5
  import requests
6
6
  from annofabapi.models import ProjectMemberRole
@@ -164,7 +164,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
164
164
  parser.set_defaults(subcommand_func=main)
165
165
 
166
166
 
167
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
167
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
168
168
  subcommand_name = "delete"
169
169
  subcommand_help = "入力データを削除します。"
170
170
  description = "入力データを削除します。"