annofabcli 1.100.4__py3-none-any.whl → 1.101.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 (29) hide show
  1. annofabcli/__init__.py +6 -4
  2. annofabcli/annotation/change_annotation_attributes.py +3 -2
  3. annofabcli/annotation/change_annotation_properties.py +8 -7
  4. annofabcli/annotation/copy_annotation.py +4 -4
  5. annofabcli/annotation/delete_annotation.py +254 -29
  6. annofabcli/annotation/dump_annotation.py +14 -7
  7. annofabcli/annotation/import_annotation.py +304 -227
  8. annofabcli/annotation/restore_annotation.py +7 -7
  9. annofabcli/annotation_specs/list_annotation_specs_attribute.py +1 -1
  10. annofabcli/annotation_specs/list_annotation_specs_choice.py +1 -1
  11. annofabcli/annotation_specs/list_annotation_specs_label.py +1 -1
  12. annofabcli/annotation_specs/list_annotation_specs_label_attribute.py +1 -1
  13. annofabcli/comment/delete_comment.py +7 -5
  14. annofabcli/comment/put_comment.py +1 -1
  15. annofabcli/comment/put_comment_simply.py +7 -5
  16. annofabcli/common/cli.py +10 -10
  17. annofabcli/common/download.py +28 -29
  18. annofabcli/common/image.py +4 -2
  19. annofabcli/input_data/delete_input_data.py +4 -4
  20. annofabcli/input_data/update_metadata_of_input_data.py +1 -1
  21. annofabcli/instruction/upload_instruction.py +2 -2
  22. annofabcli/statistics/visualize_statistics.py +1 -7
  23. annofabcli/supplementary/delete_supplementary_data.py +8 -4
  24. {annofabcli-1.100.4.dist-info → annofabcli-1.101.0.dist-info}/METADATA +8 -2
  25. {annofabcli-1.100.4.dist-info → annofabcli-1.101.0.dist-info}/RECORD +28 -29
  26. annofabcli/__version__.py +0 -7
  27. {annofabcli-1.100.4.dist-info → annofabcli-1.101.0.dist-info}/WHEEL +0 -0
  28. {annofabcli-1.100.4.dist-info → annofabcli-1.101.0.dist-info}/entry_points.txt +0 -0
  29. {annofabcli-1.100.4.dist-info → annofabcli-1.101.0.dist-info}/licenses/LICENSE +0 -0
@@ -70,7 +70,7 @@ class RestoreAnnotationMain(CommandLineWithConfirm):
70
70
  s3_path = self.service.wrapper.upload_data_to_s3(self.project_id, f, content_type="image/png")
71
71
  detail.path = s3_path
72
72
  else:
73
- logger.warning(f"annotation_id={detail.annotation_id}: data_holding_typeが'outer'なのにpathがNoneです。")
73
+ logger.warning(f"annotation_id='{detail.annotation_id}' :: data_holding_typeが'outer'なのにpathがNoneです。")
74
74
 
75
75
  return detail
76
76
 
@@ -100,7 +100,7 @@ class RestoreAnnotationMain(CommandLineWithConfirm):
100
100
 
101
101
  old_annotation, _ = self.service.api.get_editor_annotation(self.project_id, task_id, input_data_id)
102
102
 
103
- logger.info(f"task_id={task_id}, input_data_id={input_data_id} : アノテーションをリストアします。")
103
+ logger.info(f"task_id='{task_id}', input_data_id='{input_data_id}' :: アノテーションをリストアします。")
104
104
  request_body = self.parser_to_request_body(parser)
105
105
 
106
106
  updated_datetime = old_annotation["updated_datetime"] if old_annotation is not None else None
@@ -118,7 +118,7 @@ class RestoreAnnotationMain(CommandLineWithConfirm):
118
118
  success_count += 1
119
119
  except Exception: # pylint: disable=broad-except
120
120
  logger.warning(
121
- f"task_id={parser.task_id}, input_data_id={parser.input_data_id} のアノテーションのリストアに失敗しました。",
121
+ f"task_id='{parser.task_id}', input_data_id='{parser.input_data_id}' のアノテーションのリストアに失敗しました。",
122
122
  exc_info=True,
123
123
  )
124
124
 
@@ -139,10 +139,10 @@ class RestoreAnnotationMain(CommandLineWithConfirm):
139
139
  """
140
140
  logger_prefix = f"{task_index + 1!s} 件目: " if task_index is not None else ""
141
141
  task_id = task_parser.task_id
142
- if not self.confirm_processing(f"task_id={task_id} のアノテーションをリストアしますか?"):
142
+ if not self.confirm_processing(f"task_id='{task_id}' のアノテーションをリストアしますか?"):
143
143
  return False
144
144
 
145
- logger.info(f"{logger_prefix}task_id={task_id} に対して処理します。")
145
+ logger.info(f"{logger_prefix}task_id='{task_id}' に対して処理します。")
146
146
 
147
147
  task = self.service.wrapper.get_task_or_none(self.project_id, task_id)
148
148
  if task is None:
@@ -197,7 +197,7 @@ class RestoreAnnotationMain(CommandLineWithConfirm):
197
197
  try:
198
198
  return self.execute_task(task_parser, task_index=task_index)
199
199
  except Exception: # pylint: disable=broad-except
200
- logger.warning(f"task_id={task_parser.task_id} のアノテーションのリストアに失敗しました。", exc_info=True)
200
+ logger.warning(f"task_id='{task_parser.task_id}' のアノテーションのリストアに失敗しました。", exc_info=True)
201
201
  return False
202
202
 
203
203
  def main( # noqa: ANN201
@@ -246,7 +246,7 @@ class RestoreAnnotationMain(CommandLineWithConfirm):
246
246
  if result:
247
247
  success_count += 1
248
248
  except Exception:
249
- logger.warning(f"task_id={task_parser.task_id} のアノテーションのリストアに失敗しました。", exc_info=True)
249
+ logger.warning(f"task_id='{task_parser.task_id}' :: アノテーションのリストアに失敗しました。", exc_info=True)
250
250
  continue
251
251
  finally:
252
252
  task_count += 1
@@ -162,7 +162,7 @@ class PrintAnnotationSpecsAttribute(CommandLine):
162
162
  return None
163
163
  history = histories[-(before + 1)]
164
164
  logger.info(
165
- f"{history['updated_datetime']}のアノテーション仕様を出力します。history_id={history['history_id']}, comment={history['comment']}"
165
+ f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'"
166
166
  )
167
167
  return history["history_id"]
168
168
 
@@ -134,7 +134,7 @@ class PrintAnnotationSpecsAttribute(CommandLine):
134
134
  return None
135
135
  history = histories[-(before + 1)]
136
136
  logger.info(
137
- f"{history['updated_datetime']}のアノテーション仕様を出力します。history_id={history['history_id']}, comment={history['comment']}"
137
+ f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'"
138
138
  )
139
139
  return history["history_id"]
140
140
 
@@ -120,7 +120,7 @@ class PrintAnnotationSpecsLabel(CommandLine):
120
120
  return None
121
121
  history = histories[-(before + 1)]
122
122
  logger.info(
123
- f"{history['updated_datetime']}のアノテーション仕様を出力します。history_id={history['history_id']}, comment={history['comment']}"
123
+ f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'"
124
124
  )
125
125
  return history["history_id"]
126
126
 
@@ -122,7 +122,7 @@ class PrintAnnotationSpecsLabelAndAttribute(CommandLine):
122
122
  return None
123
123
  history = histories[-(before + 1)]
124
124
  logger.info(
125
- f"{history['updated_datetime']}のアノテーション仕様を出力します。history_id={history['history_id']}, comment={history['comment']}"
125
+ f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'"
126
126
  )
127
127
  return history["history_id"]
128
128
 
@@ -61,7 +61,7 @@ class DeleteCommentMain(CommandLineWithConfirm):
61
61
  for comment_id in comment_ids:
62
62
  if comment_id not in old_comment_ids:
63
63
  logger.warning(
64
- f"task_id={task['task_id']}, input_data_id={input_data_id}: comment_id='{comment_id}'のコメントは存在しません。",
64
+ f"task_id='{task['task_id']}', input_data_id='{input_data_id}' :: comment_id='{comment_id}'のコメントは存在しません。",
65
65
  )
66
66
  continue
67
67
  request_body.append(_convert(comment_id))
@@ -152,14 +152,16 @@ class DeleteCommentMain(CommandLineWithConfirm):
152
152
  self.service.api.batch_update_comments(self.project_id, task_id, input_data_id, request_body=request_body)
153
153
  added_comments_count += 1
154
154
  logger.debug(
155
- f"{logging_prefix} : task_id={task_id}, input_data_id={input_data_id}: {len(request_body)}件のコメントを削除しました。"
155
+ f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: {len(request_body)}件のコメントを削除しました。"
156
156
  )
157
157
  else:
158
- logger.warning(f"{logging_prefix} : task_id={task_id}, input_data_id={input_data_id}: 削除できるコメントは存在しませんでした。")
158
+ logger.warning(
159
+ f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: 削除できるコメントは存在しませんでした。"
160
+ )
159
161
 
160
162
  except Exception: # pylint: disable=broad-except
161
163
  logger.warning(
162
- f"{logging_prefix} : task_id={task_id}, input_data_id={input_data_id}: コメントの削除に失敗しました。",
164
+ f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: コメントの削除に失敗しました。",
163
165
  exc_info=True,
164
166
  )
165
167
 
@@ -198,7 +200,7 @@ class DeleteCommentMain(CommandLineWithConfirm):
198
200
  )
199
201
  added_comments_count += result
200
202
  except Exception: # pylint: disable=broad-except
201
- logger.warning(f"task_id={task_id}: コメントの削除に失敗しました。", exc_info=True)
203
+ logger.warning(f"task_id='{task_id}' :: コメントの削除に失敗しました。", exc_info=True)
202
204
  continue
203
205
 
204
206
  logger.info(f"{added_comments_count} / {comments_count} 件の入力データからコメントを削除しました。")
@@ -189,7 +189,7 @@ class PutCommentMain(CommandLineWithConfirm):
189
189
  )
190
190
  except Exception: # pylint: disable=broad-except
191
191
  logger.warning(
192
- f"{logging_prefix} :: task_id={task_id}, input_data_id={input_data_id}: コメントの付与に失敗しました。",
192
+ f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: コメントの付与に失敗しました。",
193
193
  exc_info=True,
194
194
  )
195
195
 
@@ -144,24 +144,26 @@ class PutCommentSimplyMain(CommandLineWithConfirm):
144
144
  # コメントを付与する
145
145
  request_body = self._create_request_body(task=changed_task, comment_info=comment_info)
146
146
  self.service.api.batch_update_comments(self.project_id, task_id, input_data_id, request_body=request_body)
147
- logger.debug(f"{logging_prefix} : task_id={task_id} のタスクにコメントを付与しました。")
147
+ logger.debug(f"{logging_prefix} :: task_id='{task_id}' のタスクにコメントを付与しました。")
148
148
  return True # noqa: TRY300
149
149
  except Exception: # pylint: disable=broad-except
150
- logger.warning(f"{logging_prefix} : task_id={task_id}, input_data_id={input_data_id}: コメントの付与に失敗しました。", exc_info=True)
150
+ logger.warning(
151
+ f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: コメントの付与に失敗しました。", exc_info=True
152
+ )
151
153
  return False
152
154
  finally:
153
155
  self.service.wrapper.change_task_status_to_break(self.project_id, task_id)
154
156
  # 担当者が変えている場合は、元に戻す
155
157
  if task["account_id"] != changed_task["account_id"]:
156
158
  self.service.wrapper.change_task_operator(self.project_id, task_id, task["account_id"])
157
- logger.debug(f"{task_id}: 担当者を元のユーザ( account_id={task['account_id']})に戻しました。")
159
+ logger.debug(f"task_id'{task_id}' :: 担当者を元のユーザ( account_id='{task['account_id']}')に戻しました。")
158
160
 
159
161
  def add_comments_for_task_wrapper(self, tpl: tuple[int, str], comment_info: AddedSimpleComment) -> bool:
160
162
  task_index, task_id = tpl
161
163
  try:
162
164
  return self.put_comment_for_task(task_id=task_id, comment_info=comment_info, task_index=task_index)
163
165
  except Exception: # pylint: disable=broad-except
164
- logger.warning(f"task_id={task_id}: コメントの付与に失敗しました。", exc_info=True)
166
+ logger.warning(f"task_id='{task_id}' :: コメントの付与に失敗しました。", exc_info=True)
165
167
  return False
166
168
 
167
169
  def put_comment_for_task_list(
@@ -191,7 +193,7 @@ class PutCommentSimplyMain(CommandLineWithConfirm):
191
193
  if result:
192
194
  success_count += 1
193
195
  except Exception: # pylint: disable=broad-except
194
- logger.warning(f"task_id={task_id}: {self.comment_type_name}の付与に失敗しました。", exc_info=True)
196
+ logger.warning(f"task_id='{task_id}' :: {self.comment_type_name}の付与に失敗しました。", exc_info=True)
195
197
  continue
196
198
 
197
199
  logger.info(f"{success_count} / {len(task_ids)} 件のタスクに{self.comment_type_name}を付与しました。")
annofabcli/common/cli.py CHANGED
@@ -397,7 +397,7 @@ class ArgumentParser:
397
397
  def __init__(self, parser: argparse.ArgumentParser) -> None:
398
398
  self.parser = parser
399
399
 
400
- def add_project_id(self, help_message: Optional[str] = None): # noqa: ANN201
400
+ def add_project_id(self, help_message: Optional[str] = None) -> None:
401
401
  """
402
402
  '--project_id` 引数を追加
403
403
  """
@@ -406,7 +406,7 @@ class ArgumentParser:
406
406
 
407
407
  self.parser.add_argument("-p", "--project_id", type=str, required=True, help=help_message)
408
408
 
409
- def add_task_id(self, required: bool = True, help_message: Optional[str] = None): # noqa: ANN201, FBT001, FBT002
409
+ def add_task_id(self, *, required: bool = True, help_message: Optional[str] = None) -> None:
410
410
  """
411
411
  '--task_id` 引数を追加
412
412
  """
@@ -415,7 +415,7 @@ class ArgumentParser:
415
415
 
416
416
  self.parser.add_argument("-t", "--task_id", type=str, required=required, nargs="+", help=help_message)
417
417
 
418
- def add_input_data_id(self, required: bool = True, help_message: Optional[str] = None): # noqa: ANN201, FBT001, FBT002
418
+ def add_input_data_id(self, *, required: bool = True, help_message: Optional[str] = None) -> None:
419
419
  """
420
420
  '--input_data_id` 引数を追加
421
421
  """
@@ -426,7 +426,7 @@ class ArgumentParser:
426
426
 
427
427
  self.parser.add_argument("-i", "--input_data_id", type=str, required=required, nargs="+", help=help_message)
428
428
 
429
- def add_format(self, choices: list[FormatArgument], default: FormatArgument, help_message: Optional[str] = None): # noqa: ANN201
429
+ def add_format(self, choices: list[FormatArgument], default: FormatArgument, help_message: Optional[str] = None) -> None:
430
430
  """
431
431
  '--format` 引数を追加
432
432
  """
@@ -435,7 +435,7 @@ class ArgumentParser:
435
435
 
436
436
  self.parser.add_argument("-f", "--format", type=str, choices=[e.value for e in choices], default=default.value, help=help_message)
437
437
 
438
- def add_csv_format(self, help_message: Optional[str] = None): # noqa: ANN201
438
+ def add_csv_format(self, help_message: Optional[str] = None) -> None:
439
439
  """
440
440
  '--csv_format` 引数を追加
441
441
  """
@@ -448,7 +448,7 @@ class ArgumentParser:
448
448
 
449
449
  self.parser.add_argument("--csv_format", type=str, help=help_message)
450
450
 
451
- def add_output(self, required: bool = False, help_message: Optional[str] = None): # noqa: ANN201, FBT001, FBT002
451
+ def add_output(self, *, required: bool = False, help_message: Optional[str] = None) -> None:
452
452
  """
453
453
  '--output` 引数を追加
454
454
  """
@@ -457,7 +457,7 @@ class ArgumentParser:
457
457
 
458
458
  self.parser.add_argument("-o", "--output", type=str, required=required, help=help_message)
459
459
 
460
- def add_task_query(self, required: bool = False, help_message: Optional[str] = None): # noqa: ANN201, FBT001, FBT002
460
+ def add_task_query(self, *, required: bool = False, help_message: Optional[str] = None) -> None:
461
461
  if help_message is None:
462
462
  help_message = (
463
463
  "タスクを絞り込むためのクエリ条件をJSON形式で指定します。"
@@ -520,7 +520,7 @@ class CommandLineWithoutWebapi:
520
520
  self.args = args
521
521
  self.process_common_args(args)
522
522
 
523
- def process_common_args(self, args: argparse.Namespace): # noqa: ANN201
523
+ def process_common_args(self, args: argparse.Namespace) -> None:
524
524
  """
525
525
  共通のコマンドライン引数を処理する。
526
526
  Args:
@@ -637,12 +637,12 @@ class CommandLine(CommandLineWithoutWebapi):
637
637
  self.facade = facade
638
638
  super().__init__(args)
639
639
 
640
- def validate_project( # noqa: ANN201
640
+ def validate_project(
641
641
  self,
642
642
  project_id: str,
643
643
  project_member_roles: Optional[list[ProjectMemberRole]] = None,
644
644
  organization_member_roles: Optional[list[OrganizationMemberRole]] = None,
645
- ):
645
+ ) -> None:
646
646
  """
647
647
  プロジェクト or 組織に対して、必要な権限が付与されているかを確認する。
648
648
 
@@ -60,26 +60,25 @@ class DownloadingFile:
60
60
  if not result:
61
61
  raise UpdatedFileForDownloadingError(f"{filetype}の更新処理が{max_wait_minutes}分以内に完了しない、または更新処理に失敗しました。")
62
62
 
63
- async def download_annotation_zip_with_async( # noqa: ANN201
63
+ async def download_annotation_zip_with_async(
64
64
  self,
65
65
  project_id: str,
66
66
  dest_path: Union[str, Path],
67
67
  is_latest: bool = False, # noqa: FBT001, FBT002
68
68
  wait_options: Optional[WaitOptions] = None,
69
- ):
69
+ ) -> None:
70
70
  loop = asyncio.get_event_loop()
71
71
  partial_func = partial(self.download_annotation_zip, project_id, dest_path, is_latest, wait_options)
72
- result = await loop.run_in_executor(None, partial_func)
73
- return result
72
+ await loop.run_in_executor(None, partial_func)
74
73
 
75
- def download_annotation_zip( # noqa: ANN201
74
+ def download_annotation_zip(
76
75
  self,
77
76
  project_id: str,
78
77
  dest_path: Union[str, Path],
79
78
  is_latest: bool = False, # noqa: FBT001, FBT002
80
79
  wait_options: Optional[WaitOptions] = None,
81
80
  should_download_full_annotation: bool = False, # noqa: FBT001, FBT002
82
- ):
81
+ ) -> None:
83
82
  """アノテーションZIPをダウンロードします。"""
84
83
 
85
84
  def download_annotation_zip(): # noqa: ANN202
@@ -103,7 +102,7 @@ class DownloadingFile:
103
102
  else:
104
103
  raise e # noqa: TRY201
105
104
 
106
- def wait_until_updated_annotation_zip(self, project_id: str, wait_options: Optional[WaitOptions] = None): # noqa: ANN201
105
+ def wait_until_updated_annotation_zip(self, project_id: str, wait_options: Optional[WaitOptions] = None) -> None:
107
106
  job_id = None
108
107
  try:
109
108
  job = self.service.api.post_annotation_archive_update(project_id)[0]["job"]
@@ -120,25 +119,24 @@ class DownloadingFile:
120
119
 
121
120
  self._wait_for_completion(project_id, job_type=ProjectJobType.GEN_ANNOTATION, wait_options=wait_options, job_id=job_id)
122
121
 
123
- async def download_input_data_json_with_async( # noqa: ANN201
122
+ async def download_input_data_json_with_async(
124
123
  self,
125
124
  project_id: str,
126
125
  dest_path: Union[str, Path],
127
126
  is_latest: bool = False, # noqa: FBT001, FBT002
128
127
  wait_options: Optional[WaitOptions] = None,
129
- ):
128
+ ) -> None:
130
129
  loop = asyncio.get_event_loop()
131
130
  partial_func = partial(self.download_input_data_json, project_id, dest_path, is_latest, wait_options)
132
- result = await loop.run_in_executor(None, partial_func)
133
- return result
131
+ await loop.run_in_executor(None, partial_func)
134
132
 
135
- def download_input_data_json( # noqa: ANN201
133
+ def download_input_data_json(
136
134
  self,
137
135
  project_id: str,
138
136
  dest_path: Union[str, Path],
139
137
  is_latest: bool = False, # noqa: FBT001, FBT002
140
138
  wait_options: Optional[WaitOptions] = None,
141
- ):
139
+ ) -> None:
142
140
  if is_latest:
143
141
  self.wait_until_updated_input_data_json(project_id, wait_options)
144
142
  self.service.wrapper.download_project_inputs_url(project_id, dest_path)
@@ -154,7 +152,7 @@ class DownloadingFile:
154
152
  else:
155
153
  raise e # noqa: TRY201
156
154
 
157
- def wait_until_updated_input_data_json(self, project_id: str, wait_options: Optional[WaitOptions] = None): # noqa: ANN201
155
+ def wait_until_updated_input_data_json(self, project_id: str, wait_options: Optional[WaitOptions] = None) -> None:
158
156
  job_id = None
159
157
  try:
160
158
  job = self.service.api.post_project_inputs_update(project_id)[0]["job"]
@@ -170,19 +168,20 @@ class DownloadingFile:
170
168
 
171
169
  self._wait_for_completion(project_id, job_type=ProjectJobType.GEN_INPUTS_LIST, wait_options=wait_options, job_id=job_id)
172
170
 
173
- async def download_task_json_with_async( # noqa: ANN201
171
+ async def download_task_json_with_async(
174
172
  self,
175
173
  project_id: str,
176
174
  dest_path: Union[str, Path],
177
175
  is_latest: bool = False, # noqa: FBT001, FBT002
178
176
  wait_options: Optional[WaitOptions] = None,
179
- ):
177
+ ) -> None:
180
178
  loop = asyncio.get_event_loop()
181
- partial_func = partial(self.download_task_json, project_id, dest_path, is_latest, wait_options)
182
- result = await loop.run_in_executor(None, partial_func)
183
- return result
179
+ partial_func = partial(self.download_task_json, project_id, dest_path, is_latest=is_latest, wait_options=wait_options)
180
+ await loop.run_in_executor(None, partial_func)
184
181
 
185
- def download_task_json(self, project_id: str, dest_path: Union[str, Path], is_latest: bool = False, wait_options: Optional[WaitOptions] = None): # noqa: ANN201, FBT001, FBT002
182
+ def download_task_json(
183
+ self, project_id: str, dest_path: Union[str, Path], *, is_latest: bool = False, wait_options: Optional[WaitOptions] = None
184
+ ) -> None:
186
185
  if is_latest:
187
186
  self.wait_until_updated_task_json(project_id, wait_options)
188
187
  self.service.wrapper.download_project_tasks_url(project_id, dest_path)
@@ -198,7 +197,7 @@ class DownloadingFile:
198
197
  else:
199
198
  raise e # noqa: TRY201
200
199
 
201
- def wait_until_updated_task_json(self, project_id: str, wait_options: Optional[WaitOptions] = None): # noqa: ANN201
200
+ def wait_until_updated_task_json(self, project_id: str, wait_options: Optional[WaitOptions] = None) -> None:
202
201
  job_id = None
203
202
  try:
204
203
  job = self.service.api.post_project_tasks_update(project_id)[0]["job"]
@@ -214,7 +213,7 @@ class DownloadingFile:
214
213
 
215
214
  self._wait_for_completion(project_id, job_type=ProjectJobType.GEN_TASKS_LIST, wait_options=wait_options, job_id=job_id)
216
215
 
217
- async def download_task_history_json_with_async(self, project_id: str, dest_path: Union[str, Path]): # noqa: ANN201
216
+ async def download_task_history_json_with_async(self, project_id: str, dest_path: Union[str, Path]) -> None:
218
217
  """
219
218
  非同期でタスク履歴全件ファイルをダウンロードする。
220
219
 
@@ -223,7 +222,7 @@ class DownloadingFile:
223
222
  """
224
223
  return self.download_task_history_json(project_id, dest_path=dest_path)
225
224
 
226
- def download_task_history_json(self, project_id: str, dest_path: Union[str, Path]): # noqa: ANN201
225
+ def download_task_history_json(self, project_id: str, dest_path: Union[str, Path]) -> None:
227
226
  """
228
227
  タスク履歴全件ファイルをダウンロードする。
229
228
 
@@ -243,7 +242,7 @@ class DownloadingFile:
243
242
  ) from e
244
243
  raise e # noqa: TRY201
245
244
 
246
- def download_task_history_event_json(self, project_id: str, dest_path: Union[str, Path]): # noqa: ANN201
245
+ def download_task_history_event_json(self, project_id: str, dest_path: Union[str, Path]) -> None:
247
246
  """
248
247
  タスク履歴イベント全件ファイルをダウンロードする。
249
248
 
@@ -263,7 +262,7 @@ class DownloadingFile:
263
262
  ) from e
264
263
  raise e # noqa: TRY201
265
264
 
266
- async def download_task_history_event_json_with_async(self, project_id: str, dest_path: Union[str, Path]): # noqa: ANN201
265
+ async def download_task_history_event_json_with_async(self, project_id: str, dest_path: Union[str, Path]) -> None:
267
266
  """
268
267
  非同期でタスク履歴全件ファイルをダウンロードする。
269
268
 
@@ -273,7 +272,7 @@ class DownloadingFile:
273
272
  """
274
273
  return self.download_task_history_event_json(project_id, dest_path=dest_path)
275
274
 
276
- async def download_inspection_json_with_async(self, project_id: str, dest_path: Union[str, Path]): # noqa: ANN201
275
+ async def download_inspection_json_with_async(self, project_id: str, dest_path: Union[str, Path]) -> None:
277
276
  """
278
277
  非同期で検査コメント全件ファイルをダウンロードする。
279
278
 
@@ -283,7 +282,7 @@ class DownloadingFile:
283
282
 
284
283
  return self.download_inspection_comment_json(project_id, dest_path=dest_path)
285
284
 
286
- def download_inspection_comment_json(self, project_id: str, dest_path: Union[str, Path]): # noqa: ANN201
285
+ def download_inspection_comment_json(self, project_id: str, dest_path: Union[str, Path]) -> None:
287
286
  """
288
287
  検査コメント全件ファイルをダウンロードする。
289
288
 
@@ -300,7 +299,7 @@ class DownloadingFile:
300
299
  ) from e
301
300
  raise e # noqa: TRY201
302
301
 
303
- async def download_comment_json_with_async(self, project_id: str, dest_path: Union[str, Path]): # noqa: ANN201
302
+ async def download_comment_json_with_async(self, project_id: str, dest_path: Union[str, Path]) -> None:
304
303
  """
305
304
  非同期でコメント全件ファイルをダウンロードする。
306
305
 
@@ -310,7 +309,7 @@ class DownloadingFile:
310
309
 
311
310
  return self.download_comment_json(project_id, dest_path=dest_path)
312
311
 
313
- def download_comment_json(self, project_id: str, dest_path: Union[str, Path]): # noqa: ANN201
312
+ def download_comment_json(self, project_id: str, dest_path: Union[str, Path]) -> None:
314
313
  """
315
314
  コメント全件ファイルをダウンロードする。
316
315
 
@@ -306,7 +306,9 @@ def write_annotation_images_from_path(
306
306
  if original_resolution is not None and (original_resolution.get("width") is not None and original_resolution.get("height") is not None):
307
307
  return original_resolution.get("width"), original_resolution.get("height")
308
308
  else:
309
- logger.warning(f"input_data_id={input_data_id}のプロパティ`system_metadata.original_resolution`には画像サイズが設定されていません。")
309
+ logger.warning(
310
+ f"input_data_id='{input_data_id}'のプロパティ`system_metadata.original_resolution`には画像サイズが設定されていません。"
311
+ )
310
312
  return None
311
313
 
312
314
  if image_size is not None:
@@ -314,7 +316,7 @@ def write_annotation_images_from_path(
314
316
  elif input_data_dict is not None:
315
317
  input_data = input_data_dict.get(input_data_id)
316
318
  if input_data is None:
317
- logger.warning(f"input_data_id={input_data_id}の入力データは存在しなかったので、スキップします。")
319
+ logger.warning(f"input_data_id='{input_data_id}'の入力データは存在しなかったので、スキップします。")
318
320
  return None
319
321
 
320
322
  return _get_image_size_from_system_metadata(input_data)
@@ -38,14 +38,14 @@ class DeleteInputData(CommandLine):
38
38
  try:
39
39
  self.service.api.delete_supplementary_data(project_id, input_data_id=input_data_id, supplementary_data_id=supplementary_data_id)
40
40
  logger.debug(
41
- f"補助情報を削除しました。input_data_id={input_data_id}, supplementary_data_id={supplementary_data_id}, "
42
- f"supplementary_data_name={supplementary_data['supplementary_data_name']}"
41
+ f"補助情報を削除しました。input_data_id='{input_data_id}', supplementary_data_id='{supplementary_data_id}', "
42
+ f"supplementary_data_name='{supplementary_data['supplementary_data_name']}'"
43
43
  )
44
44
  deleted_count += 1
45
45
  except requests.HTTPError:
46
46
  logger.warning(
47
- f"補助情報の削除に失敗しました。input_data_id={input_data_id}, supplementary_data_id={supplementary_data_id}, "
48
- f"supplementary_data_name={supplementary_data['supplementary_data_name']}",
47
+ f"補助情報の削除に失敗しました。input_data_id='{input_data_id}', supplementary_data_id='{supplementary_data_id}', "
48
+ f"supplementary_data_name='{supplementary_data['supplementary_data_name']}'",
49
49
  exc_info=True,
50
50
  )
51
51
  continue
@@ -64,7 +64,7 @@ class UpdateMetadataMain(CommandLineWithConfirm):
64
64
 
65
65
  input_data = self.service.wrapper.get_input_data_or_none(project_id, input_data_id)
66
66
  if input_data is None:
67
- logger.warning(f"{logging_prefix} 入力データは存在しないのでスキップします。input_data_id={input_data_id}")
67
+ logger.warning(f"{logging_prefix} 入力データは存在しないのでスキップします。 :: input_data_id='{input_data_id}'")
68
68
  return False
69
69
 
70
70
  logger.debug(
@@ -51,7 +51,7 @@ class UploadInstruction(CommandLine):
51
51
  作業ガイドをアップロードする
52
52
  """
53
53
 
54
- def upload_html_to_instruction(self, project_id: str, html_path: Path, temp_dir: Path): # noqa: ANN201, PLR0912
54
+ def upload_html_to_instruction(self, project_id: str, html_path: Path, temp_dir: Path) -> None: # noqa: PLR0912
55
55
  with html_path.open(encoding="utf-8") as f:
56
56
  file_content = f.read()
57
57
  pq_html = pyquery.PyQuery(file_content)
@@ -106,7 +106,7 @@ class UploadInstruction(CommandLine):
106
106
  self.update_instruction(project_id, html_data)
107
107
  logger.info("作業ガイドを更新しました。")
108
108
 
109
- def update_instruction(self, project_id: str, html_data: str): # noqa: ANN201
109
+ def update_instruction(self, project_id: str, html_data: str) -> None:
110
110
  histories, _ = self.service.api.get_instruction_history(project_id)
111
111
  if len(histories) > 0: # noqa: SIM108
112
112
  last_updated_datetime = histories[0]["updated_datetime"]
@@ -4,7 +4,6 @@ import argparse
4
4
  import functools
5
5
  import json
6
6
  import logging.handlers
7
- import re
8
7
  import sys
9
8
  import tempfile
10
9
  from multiprocessing import Pool
@@ -64,10 +63,6 @@ from annofabcli.statistics.visualization.visualization_source_files import Visua
64
63
  logger = logging.getLogger(__name__)
65
64
 
66
65
 
67
- def get_project_output_dir(project_title: str) -> str:
68
- return re.sub(r'[\\/:*?"<>|]+', "__", project_title)
69
-
70
-
71
66
  class WriteCsvGraph:
72
67
  def __init__( # noqa: PLR0913
73
68
  self,
@@ -408,8 +403,7 @@ class VisualizingStatisticsMain:
408
403
  root_output_dir: Path,
409
404
  ) -> Optional[Path]:
410
405
  try:
411
- project_title = self.facade.get_project_title(project_id)
412
- output_project_dir = root_output_dir / get_project_output_dir(project_title)
406
+ output_project_dir = root_output_dir / project_id
413
407
  self.visualize_statistics(
414
408
  project_id=project_id,
415
409
  output_project_dir=output_project_dir,
@@ -201,12 +201,12 @@ class DeleteSupplementaryDataMain(CommandLineWithConfirm):
201
201
 
202
202
 
203
203
  class DeleteSupplementaryData(CommandLine):
204
- @staticmethod
205
- def validate(args: argparse.Namespace) -> bool:
206
- COMMON_MESSAGE = "annofabcli supplementary_data put: error:" # noqa: N806
204
+ COMMON_MESSAGE = "annofabcli supplementary_data delete: error:"
205
+
206
+ def validate(self, args: argparse.Namespace) -> bool:
207
207
  if args.csv is not None: # noqa: SIM102
208
208
  if not Path(args.csv).exists():
209
- print(f"{COMMON_MESSAGE} argument --csv: ファイルパスが存在しません。 '{args.csv}'", file=sys.stderr) # noqa: T201
209
+ print(f"{self.COMMON_MESSAGE} argument --csv: ファイルパスが存在しません。 '{args.csv}'", file=sys.stderr) # noqa: T201
210
210
  return False
211
211
 
212
212
  return True
@@ -227,6 +227,10 @@ class DeleteSupplementaryData(CommandLine):
227
227
 
228
228
  elif args.json is not None:
229
229
  supplementary_data_list = annofabcli.common.cli.get_json_from_args(args.json)
230
+ if not isinstance(supplementary_data_list, list):
231
+ print(f"{self.COMMON_MESSAGE} argument --json: JSON形式が不正です。オブジェクトの配列を指定してください。", file=sys.stderr) # noqa: T201
232
+ sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
233
+
230
234
  input_data_dict = get_input_data_supplementary_data_dict_from_list(supplementary_data_list)
231
235
  main_obj.delete_supplementary_data_list(project_id, input_data_dict)
232
236
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: annofabcli
3
- Version: 1.100.4
3
+ Version: 1.101.0
4
4
  Summary: Utility Command Line Interface for AnnoFab
5
5
  Author: Kurusugawa Computer Inc.
6
6
  License: MIT
@@ -10,9 +10,14 @@ Classifier: Development Status :: 4 - Beta
10
10
  Classifier: Environment :: Console
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
13
18
  Classifier: Topic :: Utilities
14
19
  Requires-Python: >=3.9
15
- Requires-Dist: annofabapi>=1.4.1
20
+ Requires-Dist: annofabapi>=1.4.7
16
21
  Requires-Dist: bokeh<3.7,>=3.3
17
22
  Requires-Dist: dictdiffer
18
23
  Requires-Dist: isodate
@@ -25,6 +30,7 @@ Requires-Dist: python-datauri
25
30
  Requires-Dist: pyyaml
26
31
  Requires-Dist: requests
27
32
  Requires-Dist: typing-extensions>=4.5
33
+ Requires-Dist: ulid-py>=1.1.0
28
34
  Description-Content-Type: text/markdown
29
35
 
30
36
  # annofab-cli