annofabcli 1.96.0__py3-none-any.whl → 1.96.1__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.
annofabcli/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.96.0" # `poetry-dynamic-versioning`を使ってGitHubのバージョンタグを取得している。変更不要
1
+ __version__ = "1.96.1" # `poetry-dynamic-versioning`を使ってGitHubのバージョンタグを取得している。変更不要
@@ -1,7 +1,7 @@
1
1
  import argparse
2
2
  import logging
3
+ import re
3
4
  import sys
4
- import uuid
5
5
  from dataclasses import dataclass
6
6
  from functools import partial
7
7
  from multiprocessing import Pool
@@ -25,14 +25,11 @@ from annofabcli.common.cli import (
25
25
  get_json_from_args,
26
26
  prompt_yesnoall,
27
27
  )
28
- from annofabcli.common.dataclasses import WaitOptions
29
28
  from annofabcli.common.facade import AnnofabApiFacade
30
29
  from annofabcli.common.utils import get_file_scheme_path
31
30
 
32
31
  logger = logging.getLogger(__name__)
33
32
 
34
- DEFAULT_WAIT_OPTIONS = WaitOptions(interval=60, max_tries=360)
35
-
36
33
 
37
34
  @dataclass
38
35
  class CsvInputData(DataClassJsonMixin):
@@ -43,7 +40,6 @@ class CsvInputData(DataClassJsonMixin):
43
40
  input_data_name: str
44
41
  input_data_path: str
45
42
  input_data_id: Optional[str] = None
46
- sign_required: Optional[bool] = None
47
43
 
48
44
 
49
45
  @dataclass
@@ -55,7 +51,14 @@ class InputDataForPut(DataClassJsonMixin):
55
51
  input_data_name: str
56
52
  input_data_path: str
57
53
  input_data_id: str
58
- sign_required: Optional[bool]
54
+
55
+
56
+ def convert_input_data_name_to_input_data_id(input_data_name: str) -> str:
57
+ """
58
+ 入力データ名から、入力データIDを生成します。
59
+ * IDに使えない文字以外は`__`に変換する。
60
+ """
61
+ return re.sub(r"[^a-zA-Z0-9_.-]", "__", input_data_name)
59
62
 
60
63
 
61
64
  def read_input_data_csv(csv_file: Path) -> pandas.DataFrame:
@@ -64,7 +67,6 @@ def read_input_data_csv(csv_file: Path) -> pandas.DataFrame:
64
67
  * input_data_name
65
68
  * input_data_path
66
69
  * input_data_id
67
- * sign_required
68
70
 
69
71
  Args:
70
72
  csv_file (Path): CSVファイルのパス
@@ -76,6 +78,12 @@ def read_input_data_csv(csv_file: Path) -> pandas.DataFrame:
76
78
  str(csv_file),
77
79
  sep=",",
78
80
  header=None,
81
+ # names引数に"sign_required"を指定している理由:
82
+ # v1.96.0以前では、`sign_required`列を読み込んでいた。したがって、4列のCSVを使っているユーザーは存在する
83
+ # CSVの列数が`names`引数で指定した列数より大きい場合、右側から列名が割り当てられる。
84
+ # (https://qiita.com/yuji38kwmt/items/ac46c3d0ccac109410ba)
85
+ # したがって、"sign_required"がないと4列のCSVは読み込めない。
86
+ # 4列のCSVもしばらくサポートするため、"sign_required"を指定している。
79
87
  names=("input_data_name", "input_data_path", "input_data_id", "sign_required"),
80
88
  # IDと名前は必ず文字列として読み込むようにする
81
89
  dtype={"input_data_id": str, "input_data_name": str},
@@ -126,8 +134,8 @@ class SubPutInputData:
126
134
 
127
135
  file_path = get_file_scheme_path(csv_input_data.input_data_path)
128
136
  if file_path is not None:
129
- request_body.update({"input_data_name": csv_input_data.input_data_name, "sign_required": csv_input_data.sign_required})
130
- logger.debug(f"'{file_path}'を入力データとして登録します。input_data_name={csv_input_data.input_data_name}")
137
+ request_body.update({"input_data_name": csv_input_data.input_data_name})
138
+ logger.debug(f"'{file_path}'を入力データとして登録します。input_data_name='{csv_input_data.input_data_name}'")
131
139
  self.service.wrapper.put_input_data_from_file(
132
140
  project_id, input_data_id=csv_input_data.input_data_id, file_path=file_path, request_body=request_body
133
141
  )
@@ -137,7 +145,6 @@ class SubPutInputData:
137
145
  {
138
146
  "input_data_name": csv_input_data.input_data_name,
139
147
  "input_data_path": csv_input_data.input_data_path,
140
- "sign_required": csv_input_data.sign_required,
141
148
  }
142
149
  )
143
150
 
@@ -181,12 +188,13 @@ class SubPutInputData:
181
188
 
182
189
  return self.confirm_processing(message_for_confirm)
183
190
 
184
- def put_input_data_main(self, project_id: str, csv_input_data: CsvInputData, overwrite: bool = False) -> bool: # noqa: FBT001, FBT002
191
+ def put_input_data_main(self, project_id: str, csv_input_data: CsvInputData, *, overwrite: bool = False) -> bool:
185
192
  input_data = InputDataForPut(
186
193
  input_data_name=csv_input_data.input_data_name,
187
194
  input_data_path=csv_input_data.input_data_path,
188
- input_data_id=csv_input_data.input_data_id if csv_input_data.input_data_id is not None else str(uuid.uuid4()),
189
- sign_required=csv_input_data.sign_required,
195
+ input_data_id=csv_input_data.input_data_id
196
+ if csv_input_data.input_data_id is not None
197
+ else convert_input_data_name_to_input_data_id(csv_input_data.input_data_name),
190
198
  )
191
199
 
192
200
  last_updated_datetime = None
@@ -194,10 +202,10 @@ class SubPutInputData:
194
202
 
195
203
  if dict_input_data is not None:
196
204
  if overwrite:
197
- logger.debug(f"input_data_id={input_data.input_data_id} はすでに存在します。")
205
+ logger.debug(f"input_data_id='{input_data.input_data_id}' はすでに存在します。")
198
206
  last_updated_datetime = dict_input_data["updated_datetime"]
199
207
  else:
200
- logger.debug(f"input_data_id={input_data.input_data_id} がすでに存在するのでスキップします。")
208
+ logger.debug(f"input_data_id='{input_data.input_data_id}' がすでに存在するのでスキップします。")
201
209
  return False
202
210
 
203
211
  file_path = get_file_scheme_path(input_data.input_data_path)
@@ -278,14 +286,12 @@ class PutInputData(CommandLine):
278
286
 
279
287
  @staticmethod
280
288
  def get_input_data_list_from_df(df: pandas.DataFrame) -> list[CsvInputData]:
281
- def create_input_data(e: Any): # noqa: ANN202, ANN401
289
+ def create_input_data(e: Any) -> CsvInputData: # noqa: ANN401
282
290
  input_data_id = e.input_data_id if not pandas.isna(e.input_data_id) else None
283
- sign_required: Optional[bool] = e.sign_required if pandas.notna(e.sign_required) else None
284
291
  return CsvInputData(
285
292
  input_data_name=e.input_data_name,
286
293
  input_data_path=e.input_data_path,
287
294
  input_data_id=input_data_id,
288
- sign_required=sign_required,
289
295
  )
290
296
 
291
297
  input_data_list = [create_input_data(e) for e in df.itertuples()]
@@ -381,7 +387,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
381
387
  " * 1列目: input_data_name (required)\n"
382
388
  " * 2列目: input_data_path (required)\n"
383
389
  " * 3列目: input_data_id\n"
384
- " * 4列目: sign_required (bool)\n"
385
390
  ),
386
391
  )
387
392
 
@@ -400,25 +405,20 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
400
405
  parser.add_argument(
401
406
  "--overwrite",
402
407
  action="store_true",
403
- help="指定した場合、input_data_idがすでに存在していたら上書きします。指定しなければ、スキップします。"
404
- " ``--csv`` , ``--json`` を指定したときのみ有効なオプションです。",
408
+ help="指定した場合、input_data_idがすでに存在していたら上書きします。指定しなければ、スキップします。",
405
409
  )
406
410
 
407
411
  parser.add_argument(
408
412
  "--allow_duplicated_input_data",
409
413
  action="store_true",
410
- help=(
411
- "``--csv`` , ``--json`` に渡した入力データの重複(input_data_name, input_data_path)を許可します。\n"
412
- "``--csv`` , ``--json`` を指定したときのみ有効なオプションです。"
413
- ),
414
+ help=("``--csv`` , ``--json`` に渡した入力データの重複(input_data_name, input_data_path)を許可します。\n"),
414
415
  )
415
416
 
416
417
  parser.add_argument(
417
418
  "--parallelism",
418
419
  type=int,
419
420
  choices=PARALLELISM_CHOICES,
420
- help="並列度。指定しない場合は、逐次的に処理します。"
421
- "``--csv`` , ``--json`` を指定したときのみ有効なオプションです。また、必ず ``--yes`` を指定してください。",
421
+ help="並列度。指定しない場合は、逐次的に処理します。指定する場合は、 ``--yes`` も指定してください。",
422
422
  )
423
423
 
424
424
  parser.set_defaults(subcommand_func=main)
@@ -427,9 +427,8 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
427
427
  def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
428
428
  subcommand_name = "put"
429
429
  subcommand_help = "入力データを登録します。"
430
- description = "CSVに記載された情報から、入力データを登録します。"
431
430
  epilog = "オーナロールを持つユーザで実行してください。"
432
431
 
433
- parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description, epilog=epilog)
432
+ parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, epilog=epilog)
434
433
  parse_args(parser)
435
434
  return parser
@@ -142,19 +142,19 @@ def get_annotation_attribute_list_from_annotation_zipdir_path(
142
142
  def print_annotation_attribute_list_as_csv(annotation_attribute_list: list, output_file: Optional[Path]) -> None:
143
143
  df = pandas.json_normalize(annotation_attribute_list)
144
144
 
145
- # columns = [
146
- # "task_id",
147
- # "task_status"
148
- # "task_phase",
149
- # "task_phase_stage",
150
- # "input_data_id",
151
- # "input_data_name",
152
- # "annotation_id",
153
- # "label",
154
-
155
- # ]
156
-
157
- print_csv(df, output_file)
145
+ base_columns = [
146
+ "task_id",
147
+ "task_status",
148
+ "task_phase",
149
+ "task_phase_stage",
150
+ "input_data_id",
151
+ "input_data_name",
152
+ "annotation_id",
153
+ "label",
154
+ ]
155
+ attribute_columns = [col for col in df.columns if col.startswith("attributes.")]
156
+ columns = base_columns + attribute_columns
157
+ print_csv(df[columns], output_file)
158
158
 
159
159
 
160
160
  def print_annotation_attribute_list(
@@ -92,14 +92,14 @@ class DeleteSupplementaryDataMain(CommandLineWithConfirm):
92
92
  supplementary_data = _get_supplementary_data_list(supplementary_data_id)
93
93
  if supplementary_data is None:
94
94
  logger.warning(
95
- f"input_data_id={input_data_id} の入力データに、"
96
- f"supplementary_data_id={supplementary_data_id} の補助情報は存在しないのでスキップします。"
95
+ f"input_data_id='{input_data_id}' の入力データに、"
96
+ f"supplementary_data_id='{supplementary_data_id}' の補助情報は存在しないのでスキップします。"
97
97
  )
98
98
  continue
99
99
 
100
100
  message_for_confirm = (
101
- f"補助情報 supplementary_data_id={supplementary_data_id}, "
102
- f"supplementary_data_name={supplementary_data['supplementary_data_name']} を削除しますか?"
101
+ f"補助情報 supplementary_data_id='{supplementary_data_id}', "
102
+ f"supplementary_data_name='{supplementary_data['supplementary_data_name']}' を削除しますか?"
103
103
  )
104
104
  if not self.confirm_processing(message_for_confirm):
105
105
  continue
@@ -107,17 +107,17 @@ class DeleteSupplementaryDataMain(CommandLineWithConfirm):
107
107
  try:
108
108
  self.service.api.delete_supplementary_data(project_id, input_data_id=input_data_id, supplementary_data_id=supplementary_data_id)
109
109
  logger.debug(
110
- f"補助情報 supplementary_data_id={supplementary_data_id}, "
111
- f"supplementary_data_name={supplementary_data['supplementary_data_name']} を削除しました。"
112
- f"(入力データ input_data_id={input_data_id}, "
113
- f"input_data_name={input_data['input_data_name']} に紐付いている)"
110
+ f"補助情報 supplementary_data_id='{supplementary_data_id}', "
111
+ f"supplementary_data_name='{supplementary_data['supplementary_data_name']}' を削除しました。"
112
+ f"(入力データ input_data_id='{input_data_id}', "
113
+ f"input_data_name='{input_data['input_data_name']}' に紐付いている)"
114
114
  )
115
115
  deleted_count += 1
116
- except requests.HTTPError as e:
117
- logger.warning(e)
116
+ except requests.HTTPError:
118
117
  logger.warning(
119
- f"補助情報 supplementary_data_id={supplementary_data_id}, "
120
- f"supplementary_data_name={supplementary_data['supplementary_data_name']} の削除に失敗しました。"
118
+ f"補助情報 supplementary_data_id='{supplementary_data_id}', "
119
+ f"supplementary_data_name='{supplementary_data['supplementary_data_name']}' の削除に失敗しました。",
120
+ exc_info=True,
121
121
  )
122
122
  continue
123
123
  return deleted_count
@@ -128,9 +128,8 @@ class DeleteSupplementaryDataMain(CommandLineWithConfirm):
128
128
  for input_data_id, supplementary_data_id_list in input_data_dict.items():
129
129
  try:
130
130
  deleted_count += self.delete_supplementary_data_list_for_input_data(project_id, input_data_id, supplementary_data_id_list)
131
- except Exception as e: # pylint: disable=broad-except
132
- logger.warning(e)
133
- logger.warning(f"入力データ(input_data_id={input_data_id})配下の補助情報の削除に失敗しました。")
131
+ except Exception: # pylint: disable=broad-except
132
+ logger.warning(f"入力データ(input_data_id='{input_data_id}')配下の補助情報の削除に失敗しました。", exc_info=True)
134
133
 
135
134
  logger.info(f"{deleted_count} / {total_count} 件の補助情報を削除しました。")
136
135
 
@@ -155,15 +154,15 @@ class DeleteSupplementaryDataMain(CommandLineWithConfirm):
155
154
  try:
156
155
  self.service.api.delete_supplementary_data(project_id, input_data_id=input_data_id, supplementary_data_id=supplementary_data_id)
157
156
  logger.debug(
158
- f"補助情報を削除しました。input_data_id={input_data_id}, supplementary_data_id={supplementary_data_id}, "
157
+ f"補助情報を削除しました。input_data_id='{input_data_id}', supplementary_data_id='{supplementary_data_id}', "
159
158
  f"supplementary_data_name={supplementary_data['supplementary_data_name']}"
160
159
  )
161
160
  deleted_count += 1
162
- except requests.HTTPError as e:
163
- logger.warning(e)
161
+ except requests.HTTPError:
164
162
  logger.warning(
165
- f"補助情報の削除に失敗しました。input_data_id={input_data_id}, supplementary_data_id={supplementary_data_id}, "
166
- f"supplementary_data_name={supplementary_data['supplementary_data_name']}"
163
+ f"補助情報の削除に失敗しました。input_data_id='{input_data_id}', supplementary_data_id='{supplementary_data_id}', "
164
+ f"supplementary_data_name='{supplementary_data['supplementary_data_name']}'",
165
+ exc_info=True,
167
166
  )
168
167
  continue
169
168
 
@@ -174,7 +173,7 @@ class DeleteSupplementaryDataMain(CommandLineWithConfirm):
174
173
  for input_data_id in input_data_id_list:
175
174
  input_data = self.service.wrapper.get_input_data_or_none(project_id, input_data_id)
176
175
  if input_data is None:
177
- logger.warning(f"input_data_id={input_data_id} の入力データは存在しないので、補助情報の削除をスキップします。")
176
+ logger.warning(f"input_data_id='{input_data_id}' の入力データは存在しないので、補助情報の削除をスキップします。")
178
177
  continue
179
178
  input_data_name = input_data["input_data_name"]
180
179
 
@@ -202,9 +201,8 @@ class DeleteSupplementaryDataMain(CommandLineWithConfirm):
202
201
  f"input_data_name='{input_data_name}') "
203
202
  )
204
203
 
205
- except Exception as e: # pylint: disable=broad-except
206
- logger.warning(e)
207
- logger.warning(f"入力データ(input_data_id={input_data_id})配下の補助情報の削除に失敗しました。")
204
+ except Exception: # pylint: disable=broad-except
205
+ logger.warning(f"入力データ(input_data_id='{input_data_id}')配下の補助情報の削除に失敗しました。", exc_info=True)
208
206
 
209
207
  logger.info(f"{len(dict_deleted_count)} / {len(input_data_id_list)} 件の入力データに紐づく補助情報を削除しました。")
210
208
 
@@ -1,8 +1,8 @@
1
1
  import argparse
2
2
  import json
3
3
  import logging
4
+ import re
4
5
  import sys
5
- import uuid
6
6
  from dataclasses import dataclass
7
7
  from functools import partial
8
8
  from multiprocessing import Pool
@@ -32,6 +32,14 @@ from annofabcli.common.utils import get_file_scheme_path
32
32
  logger = logging.getLogger(__name__)
33
33
 
34
34
 
35
+ def convert_supplementary_data_name_to_supplementary_data_id(supplementary_data_name: str) -> str:
36
+ """
37
+ 補助情報データ名から、補助情報データIDを生成します。
38
+ * IDに使えない文字以外は`__`に変換する。
39
+ """
40
+ return re.sub(r"[^a-zA-Z0-9_.-]", "__", supplementary_data_name)
41
+
42
+
35
43
  @dataclass
36
44
  class CsvSupplementaryData(DataClassJsonMixin):
37
45
  """
@@ -71,13 +79,13 @@ class SubPutSupplementaryData:
71
79
  all_yes:
72
80
  """
73
81
 
74
- def __init__(self, service: annofabapi.Resource, facade: AnnofabApiFacade, all_yes: bool = False) -> None: # noqa: FBT001, FBT002
82
+ def __init__(self, service: annofabapi.Resource, facade: AnnofabApiFacade, *, all_yes: bool = False) -> None:
75
83
  self.service = service
76
84
  self.facade = facade
77
85
  self.all_yes = all_yes
78
86
  self.supplementary_data_cache: dict[str, list[SupplementaryData]] = {}
79
87
 
80
- def put_supplementary_data(self, project_id: str, supplementary_data: SupplementaryDataForPut): # noqa: ANN201
88
+ def put_supplementary_data(self, project_id: str, supplementary_data: SupplementaryDataForPut) -> None:
81
89
  file_path = get_file_scheme_path(supplementary_data.supplementary_data_path)
82
90
  if file_path is not None:
83
91
  request_body = {
@@ -89,7 +97,12 @@ class SubPutSupplementaryData:
89
97
  if supplementary_data.supplementary_data_type is not None:
90
98
  request_body.update({"supplementary_data_type": supplementary_data.supplementary_data_type})
91
99
 
92
- logger.debug(f"'{file_path}'を補助情報として登録します。supplementary_data_name='{supplementary_data.supplementary_data_name}'")
100
+ logger.debug(
101
+ f"'{file_path}'を補助情報として登録します。 :: "
102
+ f"input_data_id='{supplementary_data.input_data_id}', "
103
+ f"supplementary_data_id='{supplementary_data.supplementary_data_id}', "
104
+ f"supplementary_data_name='{supplementary_data.supplementary_data_name}'"
105
+ )
93
106
  self.service.wrapper.put_supplementary_data_from_file(
94
107
  project_id,
95
108
  input_data_id=supplementary_data.input_data_id,
@@ -141,10 +154,20 @@ class SubPutSupplementaryData:
141
154
 
142
155
  return yes
143
156
 
144
- def confirm_put_supplementary_data(self, csv_supplementary_data: CsvSupplementaryData, already_exists: bool = False) -> bool: # noqa: FBT001, FBT002
145
- message_for_confirm = f"supplementary_data_name='{csv_supplementary_data.supplementary_data_name}' の補助情報を登録しますか?"
157
+ def confirm_put_supplementary_data(
158
+ self, csv_supplementary_data: CsvSupplementaryData, supplementary_data_id: str, *, already_exists: bool = False
159
+ ) -> bool:
146
160
  if already_exists:
147
- message_for_confirm += f"supplementary_data_id={csv_supplementary_data.supplementary_data_id} を上書きします。"
161
+ message_for_confirm = (
162
+ f"supplementary_data_name='{csv_supplementary_data.supplementary_data_name}', "
163
+ f"supplementary_data_id='{supplementary_data_id}'の補助情報を更新しますか?"
164
+ )
165
+ else:
166
+ message_for_confirm = (
167
+ f"supplementary_data_name='{csv_supplementary_data.supplementary_data_name}', "
168
+ f"supplementary_data_id='{supplementary_data_id}'の補助情報を登録しますか?"
169
+ )
170
+
148
171
  return self.confirm_processing(message_for_confirm)
149
172
 
150
173
  def get_supplementary_data_list_cached(self, project_id: str, input_data_id: str) -> list[SupplementaryData]:
@@ -158,14 +181,14 @@ class SubPutSupplementaryData:
158
181
  cached_list = self.get_supplementary_data_list_cached(project_id, input_data_id)
159
182
  return first_true(cached_list, pred=lambda e: e["supplementary_data_id"] == supplementary_data_id)
160
183
 
161
- def get_supplementary_data_by_number(self, project_id: str, input_data_id: str, supplementary_data_number: int) -> Optional[SupplementaryData]:
162
- cached_list = self.get_supplementary_data_list_cached(project_id, input_data_id)
163
- return first_true(cached_list, pred=lambda e: e["supplementary_data_number"] == supplementary_data_number)
164
-
165
- def put_supplementary_data_main(self, project_id: str, csv_supplementary_data: CsvSupplementaryData, overwrite: bool = False) -> bool: # noqa: FBT001, FBT002
184
+ def put_supplementary_data_main(self, project_id: str, csv_supplementary_data: CsvSupplementaryData, *, overwrite: bool = False) -> bool:
166
185
  last_updated_datetime = None
167
186
  input_data_id = csv_supplementary_data.input_data_id
168
- supplementary_data_id = csv_supplementary_data.supplementary_data_id
187
+ supplementary_data_id = (
188
+ csv_supplementary_data.supplementary_data_id
189
+ if csv_supplementary_data.supplementary_data_id is not None
190
+ else convert_supplementary_data_name_to_supplementary_data_id(csv_supplementary_data.supplementary_data_name)
191
+ )
169
192
  supplementary_data_path = csv_supplementary_data.supplementary_data_path
170
193
 
171
194
  # input_data_idの存在確認
@@ -173,21 +196,20 @@ class SubPutSupplementaryData:
173
196
  logger.warning(f"input_data_id='{input_data_id}'である入力データは存在しないため、補助情報の登録をスキップします。")
174
197
  return False
175
198
 
176
- if supplementary_data_id is not None:
177
- old_supplementary_data_key = f"supplementary_data_id={supplementary_data_id}"
178
- old_supplementary_data = self.get_supplementary_data_by_id(project_id, input_data_id, supplementary_data_id)
179
- else:
180
- supplementary_data_number = csv_supplementary_data.supplementary_data_number
181
- old_supplementary_data_key = f"input_data_id={input_data_id}, supplementary_data_number={supplementary_data_number}"
182
- old_supplementary_data = self.get_supplementary_data_by_number(project_id, input_data_id, supplementary_data_number)
183
- supplementary_data_id = old_supplementary_data["supplementary_data_id"] if old_supplementary_data is not None else str(uuid.uuid4())
199
+ old_supplementary_data = self.get_supplementary_data_by_id(project_id, input_data_id, supplementary_data_id)
184
200
 
185
201
  if old_supplementary_data is not None:
186
202
  if overwrite:
187
- logger.debug(f"'{old_supplementary_data_key}' はすでに存在します。")
203
+ logger.debug(
204
+ f"supplementary_data_id='{supplementary_data_id}'である補助情報がすでに存在します。 :: "
205
+ f"input_data_id='{input_data_id}', supplementary_data_name='{csv_supplementary_data.supplementary_data_name}'"
206
+ )
188
207
  last_updated_datetime = old_supplementary_data["updated_datetime"]
189
208
  else:
190
- logger.debug(f"'{old_supplementary_data_key}' がすでに存在するのでスキップします。")
209
+ logger.debug(
210
+ f"supplementary_data_id='{supplementary_data_id}'である補助情報がすでに存在するので、補助情報の登録をスキップします。 :: "
211
+ f"input_data_id='{input_data_id}', supplementary_data_name='{csv_supplementary_data.supplementary_data_name}'"
212
+ )
191
213
  return False
192
214
 
193
215
  file_path = get_file_scheme_path(supplementary_data_path)
@@ -197,7 +219,7 @@ class SubPutSupplementaryData:
197
219
  logger.warning(f"'{supplementary_data_path}' は存在しません。")
198
220
  return False
199
221
 
200
- if not self.confirm_put_supplementary_data(csv_supplementary_data, already_exists=last_updated_datetime is not None):
222
+ if not self.confirm_put_supplementary_data(csv_supplementary_data, supplementary_data_id, already_exists=last_updated_datetime is not None):
201
223
  return False
202
224
 
203
225
  # 補助情報を登録
@@ -213,8 +235,8 @@ class SubPutSupplementaryData:
213
235
  try:
214
236
  self.put_supplementary_data(project_id, supplementary_data_for_put)
215
237
  logger.debug(
216
- f"補助情報を登録しました。"
217
- f"input_data_id='{supplementary_data_for_put.input_data_id}',"
238
+ f"補助情報を登録しました。 :: "
239
+ f"input_data_id='{supplementary_data_for_put.input_data_id}', "
218
240
  f"supplementary_data_id='{supplementary_data_for_put.supplementary_data_id}', "
219
241
  f"supplementary_data_name='{supplementary_data_for_put.supplementary_data_name}'"
220
242
  )
@@ -222,7 +244,7 @@ class SubPutSupplementaryData:
222
244
 
223
245
  except requests.exceptions.HTTPError:
224
246
  logger.warning(
225
- f"補助情報の登録に失敗しました。"
247
+ f"補助情報の登録に失敗しました。 ::"
226
248
  f"input_data_id='{supplementary_data_for_put.input_data_id}',"
227
249
  f"supplementary_data_id='{supplementary_data_for_put.supplementary_data_id}', "
228
250
  f"supplementary_data_name='{supplementary_data_for_put.supplementary_data_name}'",
@@ -240,7 +262,8 @@ class PutSupplementaryData(CommandLine):
240
262
  self,
241
263
  project_id: str,
242
264
  supplementary_data_list: list[CsvSupplementaryData],
243
- overwrite: bool = False, # noqa: FBT001, FBT002
265
+ *,
266
+ overwrite: bool = False,
244
267
  parallelism: Optional[int] = None,
245
268
  ) -> None:
246
269
  """
@@ -280,7 +303,7 @@ class PutSupplementaryData(CommandLine):
280
303
 
281
304
  @staticmethod
282
305
  def get_supplementary_data_list_from_csv(csv_path: Path) -> list[CsvSupplementaryData]:
283
- def create_supplementary_data(e: Any): # noqa: ANN202, ANN401
306
+ def create_supplementary_data(e: Any) -> CsvSupplementaryData: # noqa: ANN401
284
307
  supplementary_data_id = e.supplementary_data_id if not pandas.isna(e.supplementary_data_id) else None
285
308
  supplementary_data_type = e.supplementary_data_type if not pandas.isna(e.supplementary_data_type) else None
286
309
  return CsvSupplementaryData(
@@ -309,9 +309,10 @@ class ListTasksAddedTaskHistoryMain:
309
309
  task_list = list_task_obj.get_task_list(self.project_id, task_id_list=task_id_list, task_query=task_query)
310
310
 
311
311
  obj = AddingAdditionalInfoToTask(self.service, project_id=self.project_id)
312
+ logger.info(f"{len(task_list)} 件のタスクの履歴情報を取得します。")
312
313
 
313
314
  for index, task in enumerate(task_list):
314
- if (index + 1) % 1000 == 0:
315
+ if (index + 1) % 100 == 0:
315
316
  logger.debug(f"{index + 1} 件目のタスク履歴情報を取得します。")
316
317
 
317
318
  obj.add_additional_info_to_task(task)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annofabcli
3
- Version: 1.96.0
3
+ Version: 1.96.1
4
4
  Summary: Utility Command Line Interface for AnnoFab
5
5
  Home-page: https://github.com/kurusugawa-computer/annofab-cli
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  annofabcli/__init__.py,sha256=NMA7kFxmLlCiILQPHJa9mEuqXxtLALw_dwyXYsvz4VM,71
2
2
  annofabcli/__main__.py,sha256=JzfycqVG9ENhWOCxTouZwpHwWTSrI-grLsaMudxjyBM,5283
3
- annofabcli/__version__.py,sha256=vUosqVW-MeQrE_vPK0xlTVGwdsd_pcLlczOaCRqUXgg,132
3
+ annofabcli/__version__.py,sha256=fRMeiNR_DG_Pyx4KmlvY_dwyMYU17Xi-HyO9fioFt3g,132
4
4
  annofabcli/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  annofabcli/annotation/annotation_query.py,sha256=ke3W3RT1-WfFzwt-TXcQwGmghG34vcKJkM_jxgbNKjU,15922
6
6
  annofabcli/annotation/change_annotation_attributes.py,sha256=zHXyENZfbMGL_15xiK7Cy4cQ2sV0GjSVmKuPm3sOX7Y,17173
@@ -75,7 +75,7 @@ annofabcli/input_data/download_input_data_json.py,sha256=vxGoeM3ZEggQbWiWsrDK0_G
75
75
  annofabcli/input_data/list_all_input_data.py,sha256=Kq261WCkma5UNKfMDT7O6Z-dzzqp-KP1wL0DvHe5fH8,9879
76
76
  annofabcli/input_data/list_all_input_data_merged_task.py,sha256=UaBJW-nMHytmQ4okg69Ew1jhC2vMNnRMgl2lEBabtUI,12850
77
77
  annofabcli/input_data/list_input_data.py,sha256=RBxsHyKg1bVIEQUFDkfrq-nJmEdEYNoCjJ2L2GgSfeU,11519
78
- annofabcli/input_data/put_input_data.py,sha256=bEbo6rmLkmYTUp-ynoGUXpZoYLdBDLaZYcrxqEm74tw,17951
78
+ annofabcli/input_data/put_input_data.py,sha256=x54C-rLJVzr1YF2GlMR0w0HJReOE3E7YKiBeuh0RsTI,17934
79
79
  annofabcli/input_data/put_input_data_with_zip.py,sha256=SA4aMAwMBFgc9Lh0zmRCbmkXG4AMrcBqd5zeTSdr8lc,5566
80
80
  annofabcli/input_data/subcommand_input_data.py,sha256=X8EoxsF6PMiKrvk_r7PIe2D0WZuaPlgLJRuTiljPIdM,2048
81
81
  annofabcli/input_data/update_metadata_of_input_data.py,sha256=txdliirBrtoTabGEyWYLPclZC_DarEpRAY3MTsbViPA,11556
@@ -130,7 +130,7 @@ annofabcli/stat_visualization/write_performance_rating_csv.py,sha256=TDn7-poyFt2
130
130
  annofabcli/statistics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
131
  annofabcli/statistics/histogram.py,sha256=CvzDxT2cKLSnBGSqkZE6p92PayGxYYja1YyB24M4ALU,3245
132
132
  annofabcli/statistics/linegraph.py,sha256=0kr7jVBNMiM2ECYhv3Ry5RitElKerSl9ZKxbKzfiplI,12494
133
- annofabcli/statistics/list_annotation_attribute.py,sha256=WM0-Zw0Pm35olqrSXvbHnrb4mbC02qcjshLCrbPE3zg,12432
133
+ annofabcli/statistics/list_annotation_attribute.py,sha256=87jjNCOXJUbWnmswMCLN7GTjGsBfqpFJ6hViWmnj8Y4,12557
134
134
  annofabcli/statistics/list_annotation_count.py,sha256=xsqXxRO21MW7Wbs96PEa8gHb3i7bxjQvoMHLB2eT-0g,50360
135
135
  annofabcli/statistics/list_annotation_duration.py,sha256=9PCg1IA_g4HoHHSfsMVb2zBMLfLJ3u9Id8Qa9L8Qhko,31923
136
136
  annofabcli/statistics/list_video_duration.py,sha256=uNeMteRBX2JG_AWmcgMJj0Jzbq_qF7bvAwr25GmeIiw,9124
@@ -167,9 +167,9 @@ annofabcli/statistics/visualize_annotation_duration.py,sha256=J4Z3Ql1sdiTraMnRaR
167
167
  annofabcli/statistics/visualize_statistics.py,sha256=3bP9WRALADkAxPePa1Ix49apahi1V_qjAL6Dbrwtxd0,39550
168
168
  annofabcli/statistics/visualize_video_duration.py,sha256=A6Q91aWx7GO4F0TGxbiQI0za8BFr7IqiUaYyw3__BgY,16842
169
169
  annofabcli/supplementary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
170
- annofabcli/supplementary/delete_supplementary_data.py,sha256=StHGH7qB6mEtuD75FKRQRFdTY2Lfhnl6s4u1Jq8b-MA,13756
170
+ annofabcli/supplementary/delete_supplementary_data.py,sha256=QeOohZ6RnsxC9rKSPi0JJqJXmj99ZL17psulTqlEQFU,13738
171
171
  annofabcli/supplementary/list_supplementary_data.py,sha256=F4iJnQi_4W7S_d7ahqxWFSFcnfiKYhNuysC28v0QUWA,7649
172
- annofabcli/supplementary/put_supplementary_data.py,sha256=KLGFUIYfHmB39U7qhj6y6exU9D6XMDmYpYBKzkIxqiU,19130
172
+ annofabcli/supplementary/put_supplementary_data.py,sha256=FwFRszjcsJt-UrT2RCRAs4zzYea03CbDoiKBUZQW0zc,19581
173
173
  annofabcli/supplementary/subcommand_supplementary.py,sha256=F8qfuNQzgW5HV1QKB4h0DWN7-kPVQcoFQwPfW_vjZVk,1079
174
174
  annofabcli/task/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
175
175
  annofabcli/task/cancel_acceptance.py,sha256=rHKmAzQE1a25szVWb7dexokeW32V12bkyDIYM_oIl5U,13899
@@ -184,7 +184,7 @@ annofabcli/task/download_task_json.py,sha256=Ocjecmdf2WV_Sq3u1InfMLIsT3XSw0ojyJm
184
184
  annofabcli/task/list_all_tasks.py,sha256=F9GpzzgWffF3lUeGrFIvjweq-iEwJ1c-g8usskO_2dE,6506
185
185
  annofabcli/task/list_all_tasks_added_task_history.py,sha256=fkdiuo64iS7xxvIfGKzSiUPPEMiCVnJjjcAtMxe2Ngs,9551
186
186
  annofabcli/task/list_tasks.py,sha256=O4jjp_zdmurcGNWXFp9JXHJsH4nhlR5e3ok96YnD1SI,10237
187
- annofabcli/task/list_tasks_added_task_history.py,sha256=TVyHODV5lQuB6ALs8Xd4UUm4FYf0F6kycv7ajbm0MkQ,19583
187
+ annofabcli/task/list_tasks_added_task_history.py,sha256=7avkLYFErcdSNxGc8CQXr4FFIF1z9FtQJBSloD-tzBI,19675
188
188
  annofabcli/task/put_tasks.py,sha256=hT2xPowJmcNJhjxoAm-MFiKTw_RFcJUYlpeanegVrAU,13400
189
189
  annofabcli/task/put_tasks_by_count.py,sha256=MUHfWhqtSAXnB3O36p3bMSSgQ_3Zek9GT5qRvHGx8Lo,6041
190
190
  annofabcli/task/reject_tasks.py,sha256=5ByAN6VnKwvU5BT_cfsHwA1jLDl74bonqk3bwtnrkPU,23139
@@ -200,8 +200,8 @@ annofabcli/task_history_event/download_task_history_event_json.py,sha256=hQLVbQ0
200
200
  annofabcli/task_history_event/list_all_task_history_event.py,sha256=JQEgwOIXbbTIfeX23AVaoySHViOR9UGm9uoXuhVEBqo,6446
201
201
  annofabcli/task_history_event/list_worktime.py,sha256=9jsRYa2C9bva8E1Aqxv9CCKDuCP0MvbiaIyQFTDpjqY,13150
202
202
  annofabcli/task_history_event/subcommand_task_history_event.py,sha256=mJVJoT4RXk4HWnY7-Nrsl4If-gtaIIEXd2z7eFZwM2I,1260
203
- annofabcli-1.96.0.dist-info/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
204
- annofabcli-1.96.0.dist-info/METADATA,sha256=kHn5yPXYeuO3FK-MKUhhRcZ5vAhUakxbnLEOlqM6KsY,5626
205
- annofabcli-1.96.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
206
- annofabcli-1.96.0.dist-info/entry_points.txt,sha256=A8vlN9fiMhbYRcdBfSpl7piYzAwvkMhRXIPQUAvQFUo,55
207
- annofabcli-1.96.0.dist-info/RECORD,,
203
+ annofabcli-1.96.1.dist-info/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
204
+ annofabcli-1.96.1.dist-info/METADATA,sha256=u94b-Jzx5b2TOxFlJeBqtJbcbkkBxEgCtLomabfLhP4,5626
205
+ annofabcli-1.96.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
206
+ annofabcli-1.96.1.dist-info/entry_points.txt,sha256=A8vlN9fiMhbYRcdBfSpl7piYzAwvkMhRXIPQUAvQFUo,55
207
+ annofabcli-1.96.1.dist-info/RECORD,,