annofabcli 1.114.0__py3-none-any.whl → 1.114.2__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.
@@ -63,12 +63,13 @@ class UpdateMetadataOfTaskMain(CommandLineWithConfirm):
63
63
  task_index: int | None = None,
64
64
  ) -> bool:
65
65
  logging_prefix = f"{task_index + 1} 件目" if task_index is not None else ""
66
+ logging_prefix += f" task_id='{task_id}' :: "
66
67
  task = self.service.wrapper.get_task_or_none(project_id, task_id)
67
68
  if task is None:
68
- logger.warning(f"{logging_prefix} タスク '{task_id}' は存在しないのでスキップします。")
69
+ logger.warning(f"{logging_prefix}タスクは存在しないのでスキップします。")
69
70
  return False
70
71
 
71
- logger.debug(f"task_id='{task_id}', metadata='{json.dumps(task['metadata'])}'")
72
+ logger.debug(f"{logging_prefix}現在のmetadata='{json.dumps(task['metadata'])}'")
72
73
 
73
74
  if not self.confirm_processing(self.get_confirm_message(task_id, metadata)):
74
75
  return False
@@ -81,7 +82,7 @@ class UpdateMetadataOfTaskMain(CommandLineWithConfirm):
81
82
  request_body = {task_id: new_metadata}
82
83
  self.service.api.patch_tasks_metadata(project_id, request_body=request_body)
83
84
 
84
- logger.debug(f"{logging_prefix} タスク '{task_id}' のメタデータを更新しました。")
85
+ logger.debug(f"{logging_prefix}タスクのメタデータを更新しました。 :: 新しいmetadata={json.dumps(new_metadata)}")
85
86
  return True
86
87
 
87
88
  def set_metadata_to_task_wrapper(self, tpl: tuple[int, TaskMetadataInfo], project_id: str) -> bool:
@@ -1,6 +1,7 @@
1
1
  import argparse
2
2
  import json
3
3
  import logging
4
+ import sys
4
5
  import tempfile
5
6
  from enum import Enum
6
7
  from pathlib import Path
@@ -14,6 +15,7 @@ from annofabapi.utils import get_number_of_rejections
14
15
 
15
16
  import annofabcli.common
16
17
  from annofabcli.common.cli import (
18
+ COMMAND_LINE_ERROR_STATUS_CODE,
17
19
  ArgumentParser,
18
20
  CommandLine,
19
21
  build_annofabapi_resource_and_login,
@@ -25,6 +27,21 @@ from annofabcli.common.type_util import assert_noreturn
25
27
  logger = logging.getLogger(__name__)
26
28
 
27
29
 
30
+ class AggregationUnit(Enum):
31
+ """
32
+ 集計の単位。
33
+ """
34
+
35
+ TASK = "task_count"
36
+ """タスク数"""
37
+ INPUT_DATA = "input_data_count"
38
+ """入力データ数"""
39
+ VIDEO_DURATION_HOUR = "video_duration_hour"
40
+ """動画の長さ(時間)"""
41
+ VIDEO_DURATION_MINUTE = "video_duration_minute"
42
+ """動画の長さ(分)"""
43
+
44
+
28
45
  def isoduration_to_second(duration: str) -> float:
29
46
  """
30
47
  ISO 8601 duration を 秒に変換する
@@ -160,13 +177,21 @@ def get_step_for_current_phase(task: Task, number_of_inspections: int) -> int:
160
177
 
161
178
 
162
179
  def create_df_task(
163
- task_list: list[dict[str, Any]], task_history_dict: dict[str, list[dict[str, Any]]], not_worked_threshold_second: float = 0, metadata_keys: list[str] | None = None
180
+ task_list: list[dict[str, Any]],
181
+ task_history_dict: dict[str, list[dict[str, Any]]],
182
+ *,
183
+ not_worked_threshold_second: float = 0,
184
+ metadata_keys: list[str] | None = None,
185
+ input_data_dict: dict[str, dict[str, Any]] | None = None,
164
186
  ) -> pandas.DataFrame:
165
187
  """
166
188
  以下の列が含まれたタスクのDataFrameを生成します。
167
189
  * task_id
168
190
  * phase
169
191
  * task_status_for_summary
192
+ * input_data_count
193
+ * video_duration_hour
194
+ * video_duration_minute
170
195
  * metadata.{key} (metadata_keysで指定された各キー)
171
196
 
172
197
  Args:
@@ -174,36 +199,57 @@ def create_df_task(
174
199
  task_history_dict: タスクIDをキーとしたタスク履歴のdict
175
200
  not_worked_threshold_second: 作業していないとみなす作業時間の閾値(秒)
176
201
  metadata_keys: 集計対象のメタデータキーのリスト
202
+ input_data_dict: 入力データIDをキーとした入力データ情報のdict。動画時間を計算する場合に必要。
177
203
 
178
204
  Returns:
179
205
  タスク情報のDataFrame
180
206
  """
181
207
  metadata_keys = metadata_keys or []
208
+ input_data_dict = input_data_dict or {}
182
209
 
183
210
  for task in task_list:
184
211
  task_history = task_history_dict[task["task_id"]]
185
212
  task["task_status_for_summary"] = TaskStatusForSummary.from_task(task, task_history, not_worked_threshold_second).value
186
213
 
214
+ # 入力データ数を計算
215
+ task["input_data_count"] = len(task["input_data_id_list"])
216
+
217
+ # 動画の長さを計算
218
+ video_duration_hour = 0
219
+ video_duration_minute = 0
220
+ for input_data_id in task["input_data_id_list"]:
221
+ if input_data_id in input_data_dict:
222
+ duration = input_data_dict[input_data_id]["system_metadata"]["input_duration"]
223
+ video_duration_hour += duration / 3600
224
+ video_duration_minute += duration / 60
225
+
226
+ task["video_duration_hour"] = video_duration_hour
227
+ task["video_duration_minute"] = video_duration_minute
228
+
187
229
  # メタデータの値を抽出
188
- metadata = task.get("metadata", {})
230
+ metadata = task["metadata"]
189
231
  for key in metadata_keys:
190
- task[f"metadata.{key}"] = metadata.get(key, "")
232
+ task[f"metadata.{key}"] = metadata.get(key)
191
233
 
192
- columns = ["task_id", "phase"] + [f"metadata.{key}" for key in metadata_keys] + ["task_status_for_summary"]
234
+ columns = ["task_id", "phase", "input_data_count", "video_duration_hour", "video_duration_minute"] + [f"metadata.{key}" for key in metadata_keys] + ["task_status_for_summary"]
193
235
  df = pandas.DataFrame(task_list, columns=columns)
194
236
  return df
195
237
 
196
238
 
197
- def aggregate_df(df: pandas.DataFrame, metadata_keys: list[str] | None = None) -> pandas.DataFrame:
239
+ def aggregate_df(df: pandas.DataFrame, metadata_keys: list[str] | None = None, unit: AggregationUnit = AggregationUnit.TASK) -> pandas.DataFrame:
198
240
  """
199
- タスク数を集計する。
241
+ タスクのフェーズとステータスごとに、指定された単位で集計する。
200
242
 
201
243
  Args:
202
244
  df: 以下の列を持つDataFrame
203
245
  * phase
204
246
  * task_status_for_summary
247
+ * input_data_count
248
+ * video_duration_hour
249
+ * video_duration_minute
205
250
  * metadata.{key} (metadata_keysで指定された各キー)
206
251
  metadata_keys: 集計対象のメタデータキーのリスト
252
+ unit: 集計の単位
207
253
 
208
254
  Returns:
209
255
  indexがphase(とmetadata.*列),列がtask_status_for_summaryであるDataFrame
@@ -211,9 +257,21 @@ def aggregate_df(df: pandas.DataFrame, metadata_keys: list[str] | None = None) -
211
257
  metadata_keys = metadata_keys or []
212
258
  metadata_columns = [f"metadata.{key}" for key in metadata_keys]
213
259
 
214
- df["task_count"] = 1
260
+ # 集計対象の列を選択
261
+ match unit:
262
+ case AggregationUnit.TASK:
263
+ df["_aggregate_value"] = 1
264
+ case AggregationUnit.INPUT_DATA:
265
+ df["_aggregate_value"] = df["input_data_count"]
266
+ case AggregationUnit.VIDEO_DURATION_HOUR:
267
+ df["_aggregate_value"] = df["video_duration_hour"]
268
+ case AggregationUnit.VIDEO_DURATION_MINUTE:
269
+ df["_aggregate_value"] = df["video_duration_minute"]
270
+ case _ as unreachable:
271
+ assert_noreturn(unreachable)
272
+
215
273
  index_columns = ["phase", *metadata_columns]
216
- df2 = df.pivot_table(values="task_count", index=index_columns, columns="task_status_for_summary", aggfunc="sum", fill_value=0)
274
+ df2 = df.pivot_table(values="_aggregate_value", index=index_columns, columns="task_status_for_summary", aggfunc="sum", fill_value=0)
217
275
 
218
276
  # 列数を固定する
219
277
  for status in TaskStatusForSummary:
@@ -263,11 +321,12 @@ class GettingTaskCountSummary:
263
321
  self,
264
322
  annofab_service: AnnofabResource,
265
323
  project_id: str,
324
+ temp_dir: Path,
266
325
  *,
267
- temp_dir: Path | None = None,
268
326
  should_execute_get_tasks_api: bool = False,
269
327
  not_worked_threshold_second: float = 0,
270
328
  metadata_keys: list[str] | None = None,
329
+ unit: AggregationUnit = AggregationUnit.TASK,
271
330
  ) -> None:
272
331
  self.annofab_service = annofab_service
273
332
  self.project_id = project_id
@@ -275,6 +334,7 @@ class GettingTaskCountSummary:
275
334
  self.should_execute_get_tasks_api = should_execute_get_tasks_api
276
335
  self.not_worked_threshold_second = not_worked_threshold_second
277
336
  self.metadata_keys = metadata_keys or []
337
+ self.unit = unit
278
338
 
279
339
  def create_df_task(self) -> pandas.DataFrame:
280
340
  """
@@ -282,6 +342,9 @@ class GettingTaskCountSummary:
282
342
  * task_id
283
343
  * phase
284
344
  * task_status_for_summary
345
+ * input_data_count
346
+ * video_duration_hour
347
+ * video_duration_minute
285
348
  * metadata.{key} (metadata_keys で指定した各メタデータキーに対応する列)
286
349
  """
287
350
  if self.should_execute_get_tasks_api:
@@ -297,52 +360,60 @@ class GettingTaskCountSummary:
297
360
  task_list = self.get_task_list_with_downloading()
298
361
  task_history_dict = self.get_task_history_with_downloading()
299
362
 
300
- df = create_df_task(task_list, task_history_dict, self.not_worked_threshold_second, self.metadata_keys)
363
+ # 動画時間を集計する場合は入力データJSONをダウンロード
364
+ input_data_dict = None
365
+ if self.unit in (AggregationUnit.VIDEO_DURATION_HOUR, AggregationUnit.VIDEO_DURATION_MINUTE):
366
+ input_data_dict = self.get_input_data_dict_with_downloading()
367
+
368
+ df = create_df_task(task_list, task_history_dict, not_worked_threshold_second=self.not_worked_threshold_second, metadata_keys=self.metadata_keys, input_data_dict=input_data_dict)
301
369
  return df
302
370
 
303
- def _get_task_list_with_downloading(self, temp_dir: Path) -> list[dict[str, Any]]:
371
+ def get_task_list_with_downloading(self) -> list[dict[str, Any]]:
372
+ """
373
+ タスク全件ファイルをダウンロードしてタスク情報を取得する。
374
+ """
304
375
  downloading_obj = DownloadingFile(self.annofab_service)
305
- task_json = downloading_obj.download_task_json_to_dir(self.project_id, temp_dir)
376
+ task_json = downloading_obj.download_task_json_to_dir(self.project_id, self.temp_dir)
306
377
  with task_json.open(encoding="utf-8") as f:
307
378
  return json.load(f)
308
379
 
309
- def _get_task_history_with_downloading(self, temp_dir: Path) -> dict[str, list[dict[str, Any]]]:
380
+ def get_task_history_with_downloading(self) -> dict[str, list[dict[str, Any]]]:
381
+ """
382
+ タスク履歴全件ファイルをダウンロードしてタスク情報を取得する。
383
+ """
310
384
  downloading_obj = DownloadingFile(self.annofab_service)
311
- task_history_json = downloading_obj.download_task_history_json_to_dir(self.project_id, temp_dir)
385
+ task_history_json = downloading_obj.download_task_history_json_to_dir(self.project_id, self.temp_dir)
312
386
  with task_history_json.open(encoding="utf-8") as f:
313
387
  return json.load(f)
314
388
 
315
- def get_task_list_with_downloading(self) -> list[dict[str, Any]]:
316
- """
317
- タスク全件ファイルをダウンロードしてタスク情報を取得する。
318
- """
319
- if self.temp_dir is not None:
320
- return self._get_task_list_with_downloading(self.temp_dir)
321
- else:
322
- with tempfile.TemporaryDirectory() as str_temp_dir:
323
- return self._get_task_list_with_downloading(Path(str_temp_dir))
324
-
325
- def get_task_history_with_downloading(self) -> dict[str, list[dict[str, Any]]]:
389
+ def get_input_data_dict_with_downloading(self) -> dict[str, dict[str, Any]]:
326
390
  """
327
- タスク履歴全件ファイルをダウンロードしてタスク情報を取得する。
391
+ 入力データJSONをダウンロードして、入力データIDをキーとした辞書を返す。
328
392
  """
329
- if self.temp_dir is not None:
330
- return self._get_task_history_with_downloading(self.temp_dir)
331
- else:
332
- with tempfile.TemporaryDirectory() as str_temp_dir:
333
- return self._get_task_history_with_downloading(Path(str_temp_dir))
393
+ downloading_obj = DownloadingFile(self.annofab_service)
394
+ input_data_json = downloading_obj.download_input_data_json_to_dir(self.project_id, self.temp_dir)
395
+ with input_data_json.open(encoding="utf-8") as f:
396
+ input_data_list = json.load(f)
397
+ return {input_data["input_data_id"]: input_data for input_data in input_data_list}
334
398
 
335
399
 
336
400
  class ListTaskCountByPhase(CommandLine):
337
401
  """
338
- フェーズごとのタスク数を一覧表示する。
402
+ フェーズごとにタスク数や入力データ数などを集計し、CSV形式で出力する。
339
403
  """
340
404
 
341
405
  def list_task_count_by_phase(
342
- self, project_id: str, *, temp_dir: Path | None = None, should_execute_get_tasks_api: bool = False, not_worked_threshold_second: float = 0, metadata_keys: list[str] | None = None
406
+ self,
407
+ project_id: str,
408
+ *,
409
+ temp_dir: Path | None = None,
410
+ should_execute_get_tasks_api: bool = False,
411
+ not_worked_threshold_second: float = 0,
412
+ metadata_keys: list[str] | None = None,
413
+ unit: AggregationUnit = AggregationUnit.TASK,
343
414
  ) -> None:
344
415
  """
345
- フェーズごとのタスク数をCSV形式で出力する。
416
+ フェーズごとにタスク数や入力データ数などを集計し、CSV形式で出力する。
346
417
 
347
418
  Args:
348
419
  project_id: プロジェクトID
@@ -350,15 +421,34 @@ class ListTaskCountByPhase(CommandLine):
350
421
  should_execute_get_tasks_api: getTasks APIを実行するかどうか
351
422
  not_worked_threshold_second: 作業していないとみなす作業時間の閾値(秒)
352
423
  metadata_keys: 集計対象のメタデータキーのリスト
424
+ unit: 集計の単位
353
425
  """
354
- super().validate_project(project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
355
426
 
356
- logger.info(f"project_id='{project_id}' :: フェーズごとのタスク数を集計します。")
357
-
358
- getting_obj = GettingTaskCountSummary(
359
- self.service, project_id, temp_dir=temp_dir, should_execute_get_tasks_api=should_execute_get_tasks_api, not_worked_threshold_second=not_worked_threshold_second, metadata_keys=metadata_keys
360
- )
361
- df_task = getting_obj.create_df_task()
427
+ logger.info(f"project_id='{project_id}' :: フェーズごとの'{unit.value}'を集計します。")
428
+
429
+ if temp_dir is not None:
430
+ getting_obj = GettingTaskCountSummary(
431
+ self.service,
432
+ project_id,
433
+ temp_dir,
434
+ should_execute_get_tasks_api=should_execute_get_tasks_api,
435
+ not_worked_threshold_second=not_worked_threshold_second,
436
+ metadata_keys=metadata_keys,
437
+ unit=unit,
438
+ )
439
+ df_task = getting_obj.create_df_task()
440
+ else:
441
+ with tempfile.TemporaryDirectory() as str_temp_dir:
442
+ getting_obj = GettingTaskCountSummary(
443
+ self.service,
444
+ project_id,
445
+ Path(str_temp_dir),
446
+ should_execute_get_tasks_api=should_execute_get_tasks_api,
447
+ not_worked_threshold_second=not_worked_threshold_second,
448
+ metadata_keys=metadata_keys,
449
+ unit=unit,
450
+ )
451
+ df_task = getting_obj.create_df_task()
362
452
 
363
453
  if len(df_task) == 0:
364
454
  logger.info("タスクが0件ですが、ヘッダ行を出力します。")
@@ -377,22 +467,35 @@ class ListTaskCountByPhase(CommandLine):
377
467
  df_summary = pandas.DataFrame(columns=result_columns)
378
468
  else:
379
469
  logger.info(f"{len(df_task)} 件のタスクを集計しました。")
380
- df_summary = aggregate_df(df_task, metadata_keys)
470
+ df_summary = aggregate_df(df_task, metadata_keys, unit)
381
471
 
382
472
  self.print_csv(df_summary)
383
- logger.info(f"project_id='{project_id}' :: フェーズごとのタスク数をCSV形式で出力しました。")
473
+ logger.info(f"project_id='{project_id}' :: フェーズごとの'{unit.value}'をCSV形式で出力しました。")
384
474
 
385
475
  def main(self) -> None:
386
476
  args = self.args
387
477
  project_id = args.project_id
388
478
  temp_dir = Path(args.temp_dir) if args.temp_dir is not None else None
389
479
 
480
+ unit = AggregationUnit(args.unit)
481
+
482
+ super().validate_project(project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
483
+
484
+ # 動画時間で集計する場合は、プロジェクトが動画プロジェクトかどうかをチェック
485
+ if unit in [AggregationUnit.VIDEO_DURATION_HOUR, AggregationUnit.VIDEO_DURATION_MINUTE]:
486
+ project, _ = self.service.api.get_project(project_id)
487
+ input_data_type = project["input_data_type"]
488
+ if input_data_type != "movie":
489
+ print(f"コマンドライン引数'--unit {unit.value}' は動画プロジェクトでのみ使用できます。現在のプロジェクトの入力データタイプは'{input_data_type}'です。", file=sys.stderr) # noqa: T201
490
+ sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
491
+
390
492
  self.list_task_count_by_phase(
391
493
  project_id,
392
494
  temp_dir=temp_dir,
393
495
  should_execute_get_tasks_api=args.execute_get_tasks_api,
394
496
  not_worked_threshold_second=args.not_worked_threshold_second,
395
497
  metadata_keys=args.metadata_key,
498
+ unit=unit,
396
499
  )
397
500
 
398
501
 
@@ -427,6 +530,14 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
427
530
  help="集計対象のメタデータキーを指定します。指定したキーの値でグループ化してタスク数を集計します。",
428
531
  )
429
532
 
533
+ parser.add_argument(
534
+ "--unit",
535
+ type=str,
536
+ choices=[e.value for e in AggregationUnit],
537
+ default=AggregationUnit.TASK.value,
538
+ help="集計の単位を指定します。task_count: タスク数、input_data_count: 入力データ数、video_duration_hour: 動画の長さ(時間)、video_duration_minute: 動画の長さ(分)。",
539
+ )
540
+
430
541
  argument_parser.add_output()
431
542
 
432
543
  parser.set_defaults(subcommand_func=main)
@@ -440,7 +551,7 @@ def main(args: argparse.Namespace) -> None:
440
551
 
441
552
  def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
442
553
  subcommand_name = "list_by_phase"
443
- subcommand_help = "フェーズごとのタスク数をCSV形式で出力します。"
554
+ subcommand_help = "フェーズごとにタスク数や入力データ数などを集計し、CSV形式で出力します。"
444
555
  epilog = "オーナロールまたはアノテーションユーザーロールを持つユーザで実行してください。"
445
556
  parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, epilog=epilog)
446
557
  parse_args(parser)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: annofabcli
3
- Version: 1.114.0
3
+ Version: 1.114.2
4
4
  Summary: Utility Command Line Interface for AnnoFab
5
5
  Author: Kurusugawa Computer Inc.
6
6
  License: MIT
@@ -213,9 +213,9 @@ annofabcli/task/put_tasks.py,sha256=-v6JIXX0hGjwDWTkHLnRYr60hDHRg77Y86d-dfPymoo,
213
213
  annofabcli/task/put_tasks_by_count.py,sha256=6i7y-aH99pEDBQRWqsEQ5ESuSOL6v0SRNl3HddxLYnM,5979
214
214
  annofabcli/task/reject_tasks.py,sha256=lCpAfsU530O2TaYf8TbO4CeML7LoFgWwsCUCH6S_YC0,21924
215
215
  annofabcli/task/subcommand_task.py,sha256=vZIBXsHGc0203Q3yiSrQgNjov5MPSRyNLJ2qsFepVCA,2387
216
- annofabcli/task/update_metadata_of_task.py,sha256=Z0GF-LDt-brwgHhfz3aNYOsL4rHCf6qfzv-fzlnngOY,12817
216
+ annofabcli/task/update_metadata_of_task.py,sha256=WECoFLJ_-LWdpJ1bvzDGMh459FoLUkT8gbeLDN0JCqY,12895
217
217
  annofabcli/task_count/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
218
- annofabcli/task_count/list_by_phase.py,sha256=KkMfveSnks8Jqm_dSVzLaQMWSLIU8GAHWpOdzN7sIH4,19135
218
+ annofabcli/task_count/list_by_phase.py,sha256=IytZ9U1jOfPh0vPBvhHDTaY-G6nNK4YCsUTDSpL0K_8,23818
219
219
  annofabcli/task_count/subcommand_task_count.py,sha256=DDys_Qa4TxJarqSkJQB3zjQipSvGA7-WDNoN2HA-_JQ,735
220
220
  annofabcli/task_history/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
221
221
  annofabcli/task_history/download_task_history_json.py,sha256=mmQ0r0jGvQyeNahVeNXX8bUjOAYxP0vgBNA9Sf0QLu8,2424
@@ -227,8 +227,8 @@ annofabcli/task_history_event/download_task_history_event_json.py,sha256=lWyOoS2
227
227
  annofabcli/task_history_event/list_all_task_history_event.py,sha256=yNmvIEoNkfXXWPq9JZ3eAio82CrmELPSFg2M1yRHSzo,8017
228
228
  annofabcli/task_history_event/list_worktime.py,sha256=k6Hgy0pE2w5BtyUePN-LAyTbw0W2RMU4retwa6rC2uU,15497
229
229
  annofabcli/task_history_event/subcommand_task_history_event.py,sha256=dFllzpm8plnnwADwTV74h-R2LOA7rZW-xd2YnSkwTHo,1229
230
- annofabcli-1.114.0.dist-info/METADATA,sha256=RYGDYn-OLXZIpBecAIayJc1t3weitAg1gROOecrKXDE,4949
231
- annofabcli-1.114.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
232
- annofabcli-1.114.0.dist-info/entry_points.txt,sha256=C2uSUc-kkLJpoK_mDL5FEMAdorLEMPfwSf8VBMYnIFM,56
233
- annofabcli-1.114.0.dist-info/licenses/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
234
- annofabcli-1.114.0.dist-info/RECORD,,
230
+ annofabcli-1.114.2.dist-info/METADATA,sha256=UmgP3UTctIz_pkS4QLfuxEHW1Ae0WNQBWfK3-3n5ILI,4949
231
+ annofabcli-1.114.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
232
+ annofabcli-1.114.2.dist-info/entry_points.txt,sha256=C2uSUc-kkLJpoK_mDL5FEMAdorLEMPfwSf8VBMYnIFM,56
233
+ annofabcli-1.114.2.dist-info/licenses/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
234
+ annofabcli-1.114.2.dist-info/RECORD,,