annofabcli 1.111.2__py3-none-any.whl → 1.113.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 (186) hide show
  1. annofabcli/__main__.py +1 -2
  2. annofabcli/annotation/annotation_query.py +10 -10
  3. annofabcli/annotation/change_annotation_attributes.py +10 -10
  4. annofabcli/annotation/change_annotation_attributes_per_annotation.py +4 -5
  5. annofabcli/annotation/change_annotation_properties.py +14 -14
  6. annofabcli/annotation/copy_annotation.py +6 -6
  7. annofabcli/annotation/create_classification_annotation.py +7 -7
  8. annofabcli/annotation/delete_annotation.py +9 -9
  9. annofabcli/annotation/download_annotation_zip.py +1 -3
  10. annofabcli/annotation/dump_annotation.py +8 -8
  11. annofabcli/annotation/import_annotation.py +13 -13
  12. annofabcli/annotation/list_annotation.py +9 -9
  13. annofabcli/annotation/list_annotation_count.py +2 -3
  14. annofabcli/annotation/merge_segmentation.py +6 -6
  15. annofabcli/annotation/remove_segmentation_overlap.py +5 -5
  16. annofabcli/annotation/restore_annotation.py +7 -7
  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 +3 -3
  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 +37 -38
  35. annofabcli/annotation_zip/list_polygon_annotation.py +390 -0
  36. annofabcli/annotation_zip/list_polyline_annotation.py +402 -0
  37. annofabcli/annotation_zip/list_range_annotation.py +25 -15
  38. annofabcli/annotation_zip/list_single_point_annotation.py +25 -34
  39. annofabcli/annotation_zip/subcommand_annotation_zip.py +7 -2
  40. annofabcli/annotation_zip/validate_annotation.py +8 -7
  41. annofabcli/comment/delete_comment.py +4 -6
  42. annofabcli/comment/download_comment_json.py +4 -6
  43. annofabcli/comment/list_all_comment.py +5 -6
  44. annofabcli/comment/list_comment.py +3 -4
  45. annofabcli/comment/put_comment.py +9 -10
  46. annofabcli/comment/put_comment_simply.py +5 -6
  47. annofabcli/comment/put_inspection_comment.py +1 -3
  48. annofabcli/comment/put_inspection_comment_simply.py +1 -3
  49. annofabcli/comment/put_onhold_comment.py +1 -3
  50. annofabcli/comment/put_onhold_comment_simply.py +1 -3
  51. annofabcli/comment/subcommand_comment.py +1 -3
  52. annofabcli/common/bokeh.py +4 -4
  53. annofabcli/common/cli.py +18 -17
  54. annofabcli/common/download.py +28 -29
  55. annofabcli/common/facade.py +37 -38
  56. annofabcli/common/image.py +14 -14
  57. annofabcli/common/utils.py +8 -8
  58. annofabcli/common/visualize.py +13 -13
  59. annofabcli/experimental/list_out_of_range_annotation_for_movie.py +3 -4
  60. annofabcli/experimental/subcommand_experimental.py +1 -3
  61. annofabcli/filesystem/draw_annotation.py +27 -27
  62. annofabcli/filesystem/filter_annotation.py +9 -10
  63. annofabcli/filesystem/mask_user_info.py +15 -15
  64. annofabcli/filesystem/merge_annotation.py +9 -9
  65. annofabcli/filesystem/subcommand_filesystem.py +1 -3
  66. annofabcli/input_data/copy_input_data.py +8 -9
  67. annofabcli/input_data/delete_input_data.py +3 -3
  68. annofabcli/input_data/delete_metadata_key_of_input_data.py +3 -5
  69. annofabcli/input_data/download_input_data_json.py +4 -6
  70. annofabcli/input_data/list_all_input_data.py +9 -9
  71. annofabcli/input_data/list_all_input_data_merged_task.py +5 -5
  72. annofabcli/input_data/list_input_data.py +5 -5
  73. annofabcli/input_data/put_input_data.py +6 -6
  74. annofabcli/input_data/put_input_data_with_zip.py +3 -4
  75. annofabcli/input_data/subcommand_input_data.py +1 -3
  76. annofabcli/input_data/update_input_data.py +6 -8
  77. annofabcli/input_data/update_metadata_of_input_data.py +3 -5
  78. annofabcli/instruction/copy_instruction.py +5 -6
  79. annofabcli/instruction/download_instruction.py +5 -6
  80. annofabcli/instruction/list_instruction_history.py +3 -3
  81. annofabcli/instruction/subcommand_instruction.py +1 -3
  82. annofabcli/instruction/upload_instruction.py +3 -4
  83. annofabcli/job/delete_job.py +2 -3
  84. annofabcli/job/list_job.py +5 -5
  85. annofabcli/job/list_last_job.py +4 -4
  86. annofabcli/job/subcommand_job.py +1 -3
  87. annofabcli/job/wait_job.py +4 -5
  88. annofabcli/my_account/get_my_account.py +2 -3
  89. annofabcli/my_account/subcommand_my_account.py +1 -3
  90. annofabcli/organization/list_organization.py +2 -3
  91. annofabcli/organization/subcommand_organization.py +1 -3
  92. annofabcli/organization_member/change_organization_member.py +3 -4
  93. annofabcli/organization_member/delete_organization_member.py +3 -4
  94. annofabcli/organization_member/invite_organization_member.py +1 -3
  95. annofabcli/organization_member/list_organization_member.py +3 -3
  96. annofabcli/organization_member/subcommand_organization_member.py +1 -3
  97. annofabcli/project/change_organization_of_project.py +4 -4
  98. annofabcli/project/change_project_status.py +4 -4
  99. annofabcli/project/copy_project.py +5 -5
  100. annofabcli/project/create_project.py +8 -8
  101. annofabcli/project/diff_projects.py +4 -5
  102. annofabcli/project/list_project.py +5 -5
  103. annofabcli/project/put_project.py +2 -3
  104. annofabcli/project/subcommand_project.py +1 -2
  105. annofabcli/project/update_configuration.py +4 -4
  106. annofabcli/project/update_project.py +6 -8
  107. annofabcli/project_member/change_project_members.py +8 -8
  108. annofabcli/project_member/copy_project_members.py +4 -4
  109. annofabcli/project_member/drop_project_members.py +2 -3
  110. annofabcli/project_member/invite_project_members.py +1 -3
  111. annofabcli/project_member/list_users.py +2 -3
  112. annofabcli/project_member/put_project_members.py +6 -6
  113. annofabcli/project_member/subcommand_project_member.py +1 -3
  114. annofabcli/stat_visualization/mask_visualization_dir.py +8 -9
  115. annofabcli/stat_visualization/merge_visualization_dir.py +6 -7
  116. annofabcli/stat_visualization/subcommand_stat_visualization.py +1 -2
  117. annofabcli/stat_visualization/summarize_whole_performance_csv.py +1 -2
  118. annofabcli/stat_visualization/write_graph.py +2 -3
  119. annofabcli/stat_visualization/write_performance_rating_csv.py +20 -27
  120. annofabcli/statistics/histogram.py +5 -6
  121. annofabcli/statistics/linegraph.py +13 -14
  122. annofabcli/statistics/list_annotation_area.py +38 -13
  123. annofabcli/statistics/list_annotation_attribute.py +9 -10
  124. annofabcli/statistics/list_annotation_attribute_filled_count.py +30 -31
  125. annofabcli/statistics/list_annotation_count.py +57 -58
  126. annofabcli/statistics/list_annotation_duration.py +33 -34
  127. annofabcli/statistics/list_video_duration.py +4 -5
  128. annofabcli/statistics/list_worktime.py +4 -4
  129. annofabcli/statistics/scatter.py +9 -8
  130. annofabcli/statistics/subcommand_statistics.py +1 -4
  131. annofabcli/statistics/summarize_task_count.py +4 -6
  132. annofabcli/statistics/summarize_task_count_by_task_id_group.py +2 -4
  133. annofabcli/statistics/summarize_task_count_by_user.py +1 -3
  134. annofabcli/statistics/visualization/dataframe/annotation_count.py +5 -4
  135. annofabcli/statistics/visualization/dataframe/annotation_duration.py +2 -3
  136. annofabcli/statistics/visualization/dataframe/cumulative_productivity.py +15 -17
  137. annofabcli/statistics/visualization/dataframe/productivity_per_date.py +17 -19
  138. annofabcli/statistics/visualization/dataframe/project_performance.py +3 -12
  139. annofabcli/statistics/visualization/dataframe/task.py +11 -12
  140. annofabcli/statistics/visualization/dataframe/task_worktime_by_phase_user.py +9 -10
  141. annofabcli/statistics/visualization/dataframe/user_performance.py +21 -19
  142. annofabcli/statistics/visualization/dataframe/whole_performance.py +3 -4
  143. annofabcli/statistics/visualization/dataframe/whole_productivity_per_date.py +12 -14
  144. annofabcli/statistics/visualization/dataframe/worktime_per_date.py +11 -13
  145. annofabcli/statistics/visualization/filtering_query.py +7 -7
  146. annofabcli/statistics/visualization/project_dir.py +27 -14
  147. annofabcli/statistics/visualize_annotation_count.py +22 -23
  148. annofabcli/statistics/visualize_annotation_duration.py +21 -22
  149. annofabcli/statistics/visualize_statistics.py +36 -33
  150. annofabcli/statistics/visualize_video_duration.py +18 -20
  151. annofabcli/supplementary/delete_supplementary_data.py +5 -5
  152. annofabcli/supplementary/list_supplementary_data.py +4 -4
  153. annofabcli/supplementary/put_supplementary_data.py +9 -9
  154. annofabcli/supplementary/subcommand_supplementary.py +1 -3
  155. annofabcli/task/cancel_acceptance.py +16 -17
  156. annofabcli/task/change_operator.py +10 -12
  157. annofabcli/task/change_status_to_break.py +7 -9
  158. annofabcli/task/change_status_to_on_hold.py +10 -12
  159. annofabcli/task/complete_tasks.py +17 -18
  160. annofabcli/task/copy_tasks.py +3 -5
  161. annofabcli/task/delete_metadata_key_of_task.py +4 -6
  162. annofabcli/task/delete_tasks.py +7 -7
  163. annofabcli/task/download_task_json.py +4 -6
  164. annofabcli/task/list_all_tasks.py +8 -8
  165. annofabcli/task/list_all_tasks_added_task_history.py +14 -13
  166. annofabcli/task/list_tasks.py +7 -7
  167. annofabcli/task/list_tasks_added_task_history.py +10 -10
  168. annofabcli/task/put_tasks.py +5 -6
  169. annofabcli/task/put_tasks_by_count.py +2 -3
  170. annofabcli/task/reject_tasks.py +18 -20
  171. annofabcli/task/subcommand_task.py +1 -3
  172. annofabcli/task/update_metadata_of_task.py +5 -6
  173. annofabcli/task_history/download_task_history_json.py +4 -6
  174. annofabcli/task_history/list_all_task_history.py +6 -7
  175. annofabcli/task_history/list_task_history.py +4 -5
  176. annofabcli/task_history/subcommand_task_history.py +1 -3
  177. annofabcli/task_history_event/download_task_history_event_json.py +4 -6
  178. annofabcli/task_history_event/list_all_task_history_event.py +7 -7
  179. annofabcli/task_history_event/list_worktime.py +17 -16
  180. annofabcli/task_history_event/subcommand_task_history_event.py +1 -2
  181. {annofabcli-1.111.2.dist-info → annofabcli-1.113.0.dist-info}/METADATA +9 -15
  182. annofabcli-1.113.0.dist-info/RECORD +231 -0
  183. {annofabcli-1.111.2.dist-info → annofabcli-1.113.0.dist-info}/WHEEL +1 -1
  184. annofabcli-1.111.2.dist-info/RECORD +0 -228
  185. {annofabcli-1.111.2.dist-info → annofabcli-1.113.0.dist-info}/entry_points.txt +0 -0
  186. {annofabcli-1.111.2.dist-info → annofabcli-1.113.0.dist-info}/licenses/LICENSE +0 -0
@@ -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,17 +4,17 @@ 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
14
14
  from dataclasses_json import DataClassJsonMixin
15
15
  from PIL import Image, ImageColor, ImageDraw
16
16
 
17
- import annofabcli
17
+ import annofabcli.common.cli
18
18
  from annofabcli.common.cli import (
19
19
  COMMAND_LINE_ERROR_STATUS_CODE,
20
20
  ArgumentParser,
@@ -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,12 +2,12 @@ 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
9
9
 
10
- import annofabcli
10
+ import annofabcli.common.cli
11
11
  from annofabcli.common.cli import ArgumentParser, CommandLineWithoutWebapi, get_list_from_args
12
12
  from annofabcli.common.utils import read_multiheader_csv
13
13
 
@@ -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,
@@ -15,7 +15,7 @@ from annofabapi.parser import (
15
15
  lazy_parse_simple_annotation_zip,
16
16
  )
17
17
 
18
- import annofabcli
18
+ import annofabcli.common.cli
19
19
  from annofabcli.common.cli import (
20
20
  COMMAND_LINE_ERROR_STATUS_CODE,
21
21
  ArgumentParser,
@@ -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,11 +1,11 @@
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
7
7
 
8
- import annofabcli
8
+ import annofabcli.common.cli
9
9
  from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login
10
10
  from annofabcli.common.facade import AnnofabApiFacade
11
11
 
@@ -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 = "入力データを削除します。"
@@ -8,12 +8,10 @@ import multiprocessing
8
8
  import sys
9
9
  from collections.abc import Collection
10
10
  from functools import partial
11
- from typing import Optional
12
11
 
13
12
  import annofabapi
14
13
  from annofabapi.models import ProjectMemberRole
15
14
 
16
- import annofabcli
17
15
  import annofabcli.common.cli
18
16
  from annofabcli.common.cli import (
19
17
  COMMAND_LINE_ERROR_STATUS_CODE,
@@ -40,7 +38,7 @@ class DeleteMetadataKeyOfInputDataMain(CommandLineWithConfirm):
40
38
  self.project_id = project_id
41
39
  super().__init__(all_yes=all_yes)
42
40
 
43
- def delete_metadata_keys_for_one_input_data(self, input_data_id: str, metadata_keys: Collection[str], *, input_data_index: Optional[int] = None) -> bool:
41
+ def delete_metadata_keys_for_one_input_data(self, input_data_id: str, metadata_keys: Collection[str], *, input_data_index: int | None = None) -> bool:
44
42
  """
45
43
  1個の入力データに対して、メタデータのキーを削除します。
46
44
 
@@ -100,7 +98,7 @@ class DeleteMetadataKeyOfInputDataMain(CommandLineWithConfirm):
100
98
  logger.warning(f"input_data_id='{input_data_id}' :: 入力データのメタデータのキーを削除するのに失敗しました。", exc_info=True)
101
99
  return False
102
100
 
103
- def delete_metadata_keys_for_input_data_list(self, input_data_id_list: list[str], metadata_keys: Collection[str], *, parallelism: Optional[int] = None) -> None:
101
+ def delete_metadata_keys_for_input_data_list(self, input_data_id_list: list[str], metadata_keys: Collection[str], *, parallelism: int | None = None) -> None:
104
102
  logger.info(f"{len(input_data_id_list)} 件の入力データのメタデータから、キー'{metadata_keys}'を削除します。")
105
103
 
106
104
  success_count = 0
@@ -185,7 +183,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
185
183
  parser.set_defaults(subcommand_func=main)
186
184
 
187
185
 
188
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
186
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
189
187
  subcommand_name = "delete_metadata_key"
190
188
  subcommand_help = "入力データのメタデータのキーを削除します。"
191
189
  epilog = "オーナロールを持つユーザで実行してください。"
@@ -1,11 +1,9 @@
1
1
  import argparse
2
2
  import logging
3
3
  from pathlib import Path
4
- from typing import Optional
5
4
 
6
5
  from annofabapi.models import ProjectMemberRole
7
6
 
8
- import annofabcli
9
7
  import annofabcli.common.cli
10
8
  from annofabcli.common.cli import CommandLine, build_annofabapi_resource_and_login
11
9
  from annofabcli.common.download import DownloadingFile
@@ -15,10 +13,10 @@ logger = logging.getLogger(__name__)
15
13
 
16
14
 
17
15
  class DownloadingInputData(CommandLine):
18
- def download_input_data_json(self, project_id: str, output_file: Path, is_latest: bool): # noqa: ANN201, FBT001
16
+ def download_input_data_json(self, project_id: str, output_file: Path, is_latest: bool) -> None: # noqa: FBT001
19
17
  super().validate_project(project_id, [ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
20
18
  project_title = self.facade.get_project_title(project_id)
21
- logger.info(f"{project_title} の入力データ全件ファイルをダウンロードします。")
19
+ logger.info(f"project_id='{project_id}'の入力データ全件ファイルをダウンロードします。 :: project_title='{project_title}'")
22
20
 
23
21
  obj = DownloadingFile(self.service)
24
22
  obj.download_input_data_json(
@@ -26,7 +24,7 @@ class DownloadingInputData(CommandLine):
26
24
  str(output_file),
27
25
  is_latest=is_latest,
28
26
  )
29
- logger.info(f"入力データ全件ファイルをダウンロードしました。output={output_file}")
27
+ logger.info(f"project_id='{project_id}'の入力データ全件ファイルをダウンロードしました。 :: output='{output_file}', project_title='{project_title}'")
30
28
 
31
29
  def main(self) -> None:
32
30
  args = self.args
@@ -58,7 +56,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
58
56
  parser.set_defaults(subcommand_func=main)
59
57
 
60
58
 
61
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
59
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
62
60
  subcommand_name = "download"
63
61
  subcommand_help = "入力データ全件ファイルをダウンロードします。"
64
62
  epilog = "オーナロールまたはアノテーションユーザロールを持つユーザで実行してください。"
@@ -6,14 +6,14 @@ import json
6
6
  import logging
7
7
  import tempfile
8
8
  from pathlib import Path
9
- from typing import Any, Optional
9
+ from typing import Any
10
10
 
11
11
  import annofabapi
12
12
  import pandas
13
13
  from annofabapi.dataclass.input import InputData
14
14
  from annofabapi.models import ProjectMemberRole
15
15
 
16
- import annofabcli
16
+ import annofabcli.common.cli
17
17
  from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login, print_according_to_format, print_csv
18
18
  from annofabcli.common.download import DownloadingFile
19
19
  from annofabcli.common.enums import FormatArgument
@@ -23,7 +23,7 @@ from annofabcli.input_data.utils import remove_unnecessary_keys_from_input_data
23
23
 
24
24
  logger = logging.getLogger(__name__)
25
25
 
26
- DatetimeRange = tuple[Optional[datetime.datetime], Optional[datetime.datetime]]
26
+ DatetimeRange = tuple[datetime.datetime | None, datetime.datetime | None]
27
27
 
28
28
 
29
29
  class ListInputDataWithJsonMain:
@@ -33,8 +33,8 @@ class ListInputDataWithJsonMain:
33
33
  @staticmethod
34
34
  def filter_input_data_list(
35
35
  input_data: dict[str, Any],
36
- input_data_id_set: Optional[set[str]] = None,
37
- input_data_query: Optional[InputDataQuery] = None,
36
+ input_data_id_set: set[str] | None = None,
37
+ input_data_query: InputDataQuery | None = None,
38
38
  ) -> bool:
39
39
  result = True
40
40
 
@@ -64,10 +64,10 @@ class ListInputDataWithJsonMain:
64
64
  def get_input_data_list(
65
65
  self,
66
66
  project_id: str,
67
- input_data_json: Optional[Path],
67
+ input_data_json: Path | None,
68
68
  *,
69
- input_data_id_list: Optional[list[str]] = None,
70
- input_data_query: Optional[InputDataQuery] = None,
69
+ input_data_id_list: list[str] | None = None,
70
+ input_data_query: InputDataQuery | None = None,
71
71
  contain_parent_task_id_list: bool = False,
72
72
  contain_supplementary_data_count: bool = False,
73
73
  is_latest: bool = False,
@@ -209,7 +209,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
209
209
  parser.set_defaults(subcommand_func=main)
210
210
 
211
211
 
212
- def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
212
+ def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
213
213
  subcommand_name = "list_all"
214
214
  subcommand_help = "すべての入力データの一覧を出力します。"
215
215
  description = "すべての入力データの一覧を出力します。\n出力される入力データは、コマンドを実行した日の02:00(JST)頃の状態です。最新の情報を出力したい場合は、 ``--latest`` を指定してください。"