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.
- annofabcli/task/update_metadata_of_task.py +4 -3
- annofabcli/task_count/list_by_phase.py +155 -44
- {annofabcli-1.114.0.dist-info → annofabcli-1.114.2.dist-info}/METADATA +1 -1
- {annofabcli-1.114.0.dist-info → annofabcli-1.114.2.dist-info}/RECORD +7 -7
- {annofabcli-1.114.0.dist-info → annofabcli-1.114.2.dist-info}/WHEEL +0 -0
- {annofabcli-1.114.0.dist-info → annofabcli-1.114.2.dist-info}/entry_points.txt +0 -0
- {annofabcli-1.114.0.dist-info → annofabcli-1.114.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -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}
|
|
69
|
+
logger.warning(f"{logging_prefix}タスクは存在しないのでスキップします。")
|
|
69
70
|
return False
|
|
70
71
|
|
|
71
|
-
logger.debug(f"
|
|
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}
|
|
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]],
|
|
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
|
|
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
|
-
|
|
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="
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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}' ::
|
|
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 = "
|
|
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)
|
|
@@ -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=
|
|
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=
|
|
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.
|
|
231
|
-
annofabcli-1.114.
|
|
232
|
-
annofabcli-1.114.
|
|
233
|
-
annofabcli-1.114.
|
|
234
|
-
annofabcli-1.114.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|