annofabcli 1.102.1__py3-none-any.whl → 1.104.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.
- annofabcli/__main__.py +1 -1
- annofabcli/annotation/annotation_query.py +9 -29
- annofabcli/annotation/change_annotation_attributes.py +6 -14
- annofabcli/annotation/change_annotation_properties.py +5 -12
- annofabcli/annotation/copy_annotation.py +4 -10
- annofabcli/annotation/delete_annotation.py +10 -26
- annofabcli/annotation/dump_annotation.py +1 -4
- annofabcli/annotation/import_annotation.py +15 -39
- annofabcli/annotation/list_annotation.py +1 -4
- annofabcli/annotation/merge_segmentation.py +5 -15
- annofabcli/annotation/remove_segmentation_overlap.py +8 -29
- annofabcli/annotation/restore_annotation.py +3 -9
- annofabcli/annotation_specs/add_attribute_restriction.py +2 -8
- annofabcli/annotation_specs/attribute_restriction.py +2 -10
- annofabcli/annotation_specs/export_annotation_specs.py +1 -3
- annofabcli/annotation_specs/get_annotation_specs_with_attribute_id_replaced.py +3 -10
- annofabcli/annotation_specs/get_annotation_specs_with_choice_id_replaced.py +4 -10
- annofabcli/annotation_specs/get_annotation_specs_with_label_id_replaced.py +1 -3
- annofabcli/annotation_specs/list_annotation_specs_attribute.py +7 -18
- annofabcli/annotation_specs/list_annotation_specs_choice.py +3 -8
- annofabcli/annotation_specs/list_annotation_specs_history.py +0 -1
- annofabcli/annotation_specs/list_annotation_specs_label.py +3 -8
- annofabcli/annotation_specs/list_annotation_specs_label_attribute.py +4 -9
- annofabcli/annotation_specs/list_attribute_restriction.py +3 -9
- annofabcli/annotation_specs/put_label_color.py +1 -6
- annofabcli/comment/delete_comment.py +3 -9
- annofabcli/comment/list_all_comment.py +15 -5
- annofabcli/comment/list_comment.py +46 -7
- annofabcli/comment/put_comment.py +4 -13
- annofabcli/comment/put_comment_simply.py +2 -6
- annofabcli/comment/put_inspection_comment.py +2 -6
- annofabcli/comment/put_inspection_comment_simply.py +3 -6
- annofabcli/comment/put_onhold_comment.py +2 -6
- annofabcli/comment/put_onhold_comment_simply.py +2 -4
- annofabcli/common/cli.py +5 -43
- annofabcli/common/download.py +8 -25
- annofabcli/common/image.py +3 -7
- annofabcli/common/utils.py +2 -4
- annofabcli/common/visualize.py +2 -4
- annofabcli/filesystem/draw_annotation.py +6 -18
- annofabcli/filesystem/filter_annotation.py +7 -24
- annofabcli/filesystem/mask_user_info.py +2 -5
- annofabcli/filesystem/merge_annotation.py +2 -6
- annofabcli/input_data/change_input_data_name.py +3 -7
- annofabcli/input_data/copy_input_data.py +6 -14
- annofabcli/input_data/delete_input_data.py +7 -24
- annofabcli/input_data/delete_metadata_key_of_input_data.py +5 -16
- annofabcli/input_data/list_all_input_data.py +5 -14
- annofabcli/input_data/list_all_input_data_merged_task.py +8 -23
- annofabcli/input_data/list_input_data.py +5 -16
- annofabcli/input_data/put_input_data.py +7 -19
- annofabcli/input_data/update_metadata_of_input_data.py +6 -14
- annofabcli/instruction/list_instruction_history.py +0 -1
- annofabcli/instruction/upload_instruction.py +4 -7
- annofabcli/job/list_job.py +2 -3
- annofabcli/job/list_last_job.py +1 -3
- annofabcli/organization/list_organization.py +0 -1
- annofabcli/organization_member/change_organization_member.py +1 -3
- annofabcli/organization_member/delete_organization_member.py +2 -6
- annofabcli/organization_member/invite_organization_member.py +1 -3
- annofabcli/organization_member/list_organization_member.py +0 -1
- annofabcli/project/change_organization_of_project.py +257 -0
- annofabcli/project/change_project_status.py +2 -2
- annofabcli/project/copy_project.py +2 -7
- annofabcli/project/diff_projects.py +4 -16
- annofabcli/project/list_project.py +0 -1
- annofabcli/project/put_project.py +2 -6
- annofabcli/project/subcommand_project.py +2 -0
- annofabcli/project_member/change_project_members.py +1 -1
- annofabcli/project_member/copy_project_members.py +2 -7
- annofabcli/project_member/drop_project_members.py +1 -3
- annofabcli/project_member/invite_project_members.py +2 -4
- annofabcli/project_member/list_users.py +0 -1
- annofabcli/project_member/put_project_members.py +4 -12
- annofabcli/stat_visualization/mask_visualization_dir.py +6 -16
- annofabcli/stat_visualization/merge_visualization_dir.py +7 -19
- annofabcli/stat_visualization/summarize_whole_performance_csv.py +3 -7
- annofabcli/stat_visualization/write_graph.py +5 -15
- annofabcli/stat_visualization/write_performance_rating_csv.py +4 -12
- annofabcli/statistics/list_annotation_area.py +3 -7
- annofabcli/statistics/list_annotation_attribute.py +6 -15
- annofabcli/statistics/list_annotation_attribute_filled_count.py +9 -23
- annofabcli/statistics/list_annotation_count.py +18 -44
- annofabcli/statistics/list_annotation_duration.py +14 -40
- annofabcli/statistics/list_video_duration.py +2 -3
- annofabcli/statistics/list_worktime.py +0 -1
- annofabcli/statistics/scatter.py +3 -9
- annofabcli/statistics/summarize_task_count.py +7 -12
- annofabcli/statistics/summarize_task_count_by_task_id_group.py +3 -11
- annofabcli/statistics/summarize_task_count_by_user.py +1 -5
- annofabcli/statistics/visualization/dataframe/annotation_count.py +2 -4
- annofabcli/statistics/visualization/dataframe/cumulative_productivity.py +6 -12
- annofabcli/statistics/visualization/dataframe/productivity_per_date.py +10 -22
- annofabcli/statistics/visualization/dataframe/project_performance.py +1 -3
- annofabcli/statistics/visualization/dataframe/task.py +2 -5
- annofabcli/statistics/visualization/dataframe/task_history.py +1 -1
- annofabcli/statistics/visualization/dataframe/task_worktime_by_phase_user.py +6 -20
- annofabcli/statistics/visualization/dataframe/user_performance.py +29 -88
- annofabcli/statistics/visualization/dataframe/whole_performance.py +6 -12
- annofabcli/statistics/visualization/dataframe/whole_productivity_per_date.py +17 -49
- annofabcli/statistics/visualization/dataframe/worktime_per_date.py +4 -10
- annofabcli/statistics/visualization/filtering_query.py +2 -6
- annofabcli/statistics/visualization/project_dir.py +9 -26
- annofabcli/statistics/visualization/visualization_source_files.py +3 -10
- annofabcli/statistics/visualize_annotation_count.py +9 -23
- annofabcli/statistics/visualize_annotation_duration.py +5 -15
- annofabcli/statistics/visualize_statistics.py +18 -53
- annofabcli/statistics/visualize_video_duration.py +8 -19
- annofabcli/supplementary/delete_supplementary_data.py +7 -23
- annofabcli/supplementary/list_supplementary_data.py +1 -1
- annofabcli/supplementary/put_supplementary_data.py +5 -15
- annofabcli/task/cancel_acceptance.py +3 -4
- annofabcli/task/change_operator.py +3 -11
- annofabcli/task/change_status_to_break.py +1 -1
- annofabcli/task/change_status_to_on_hold.py +5 -18
- annofabcli/task/complete_tasks.py +8 -25
- annofabcli/task/copy_tasks.py +2 -3
- annofabcli/task/delete_metadata_key_of_task.py +2 -6
- annofabcli/task/delete_tasks.py +8 -26
- annofabcli/task/list_all_tasks.py +2 -4
- annofabcli/task/list_tasks.py +3 -7
- annofabcli/task/list_tasks_added_task_history.py +7 -21
- annofabcli/task/put_tasks.py +2 -3
- annofabcli/task/put_tasks_by_count.py +3 -7
- annofabcli/task/reject_tasks.py +7 -19
- annofabcli/task/update_metadata_of_task.py +2 -2
- annofabcli/task_history/list_all_task_history.py +2 -5
- annofabcli/task_history/list_task_history.py +0 -1
- annofabcli/task_history_event/list_all_task_history_event.py +4 -11
- annofabcli/task_history_event/list_worktime.py +4 -14
- {annofabcli-1.102.1.dist-info → annofabcli-1.104.0.dist-info}/METADATA +1 -1
- annofabcli-1.104.0.dist-info/RECORD +215 -0
- annofabcli-1.102.1.dist-info/RECORD +0 -214
- {annofabcli-1.102.1.dist-info → annofabcli-1.104.0.dist-info}/WHEEL +0 -0
- {annofabcli-1.102.1.dist-info → annofabcli-1.104.0.dist-info}/entry_points.txt +0 -0
- {annofabcli-1.102.1.dist-info → annofabcli-1.104.0.dist-info}/licenses/LICENSE +0 -0
annofabcli/task/delete_tasks.py
CHANGED
|
@@ -53,9 +53,7 @@ class DeleteTaskMain(CommandLineWithConfirm):
|
|
|
53
53
|
supplementary_data_id = supplementary_data["supplementary_data_id"]
|
|
54
54
|
try:
|
|
55
55
|
if not self.dryrun:
|
|
56
|
-
self.service.api.delete_supplementary_data(
|
|
57
|
-
self.project_id, input_data_id=input_data_id, supplementary_data_id=supplementary_data_id
|
|
58
|
-
)
|
|
56
|
+
self.service.api.delete_supplementary_data(self.project_id, input_data_id=input_data_id, supplementary_data_id=supplementary_data_id)
|
|
59
57
|
logger.debug(
|
|
60
58
|
f"task_id='{task_id}', input_data_id='{input_data_id}' :: 補助情報を削除しました。 :: "
|
|
61
59
|
f"supplementary_data_id='{supplementary_data_id}', "
|
|
@@ -71,18 +69,12 @@ class DeleteTaskMain(CommandLineWithConfirm):
|
|
|
71
69
|
)
|
|
72
70
|
continue
|
|
73
71
|
|
|
74
|
-
logger.debug(
|
|
75
|
-
f"task_id='{task_id}', input_data_id='{input_data_id}' :: 補助情報 {deleted_count} / {len(supplementary_data_list)} 件を削除しました。"
|
|
76
|
-
)
|
|
72
|
+
logger.debug(f"task_id='{task_id}', input_data_id='{input_data_id}' :: 補助情報 {deleted_count} / {len(supplementary_data_list)} 件を削除しました。")
|
|
77
73
|
|
|
78
74
|
return deleted_count
|
|
79
75
|
|
|
80
76
|
def confirm_deleting_input_data(self, task_id: str, input_data_id: str, input_data_name: str) -> bool:
|
|
81
|
-
message_for_confirm =
|
|
82
|
-
f"task_id='{task_id}'のタスクから参照されている入力データと補助情報を削除しますか? :: "
|
|
83
|
-
f"input_data_id='{input_data_id}', "
|
|
84
|
-
f"input_data_name='{input_data_name}'"
|
|
85
|
-
)
|
|
77
|
+
message_for_confirm = f"task_id='{task_id}'のタスクから参照されている入力データと補助情報を削除しますか? :: input_data_id='{input_data_id}', input_data_name='{input_data_name}'"
|
|
86
78
|
return self.confirm_processing(message_for_confirm)
|
|
87
79
|
|
|
88
80
|
def delete_input_data_and_supplementary_data(self, task_id: str, input_data_id: str) -> bool:
|
|
@@ -98,10 +90,7 @@ class DeleteTaskMain(CommandLineWithConfirm):
|
|
|
98
90
|
other_task_list = [e for e in task_list if e["task_id"] != task_id and input_data_id in e["input_data_id_list"]]
|
|
99
91
|
if len(other_task_list) > 0:
|
|
100
92
|
other_task_id_list = [e["task_id"] for e in other_task_list]
|
|
101
|
-
logger.info(
|
|
102
|
-
f"task_id='{task_id}' :: input_data_id='{input_data_id}'の入力データは、"
|
|
103
|
-
f"他のタスクから参照されているため、削除しません。 :: 参照しているタスク = {other_task_id_list}"
|
|
104
|
-
)
|
|
93
|
+
logger.info(f"task_id='{task_id}' :: input_data_id='{input_data_id}'の入力データは、他のタスクから参照されているため、削除しません。 :: 参照しているタスク = {other_task_id_list}")
|
|
105
94
|
return False
|
|
106
95
|
|
|
107
96
|
input_data, _ = self.service.api.get_input_data(self.project_id, input_data_id)
|
|
@@ -114,9 +103,7 @@ class DeleteTaskMain(CommandLineWithConfirm):
|
|
|
114
103
|
# 入力データに紐づく補助情報を削除
|
|
115
104
|
if not self.dryrun:
|
|
116
105
|
self.service.api.delete_input_data(self.project_id, input_data_id)
|
|
117
|
-
logger.debug(
|
|
118
|
-
f"task_id='{task_id}' :: 入力データを削除しました。 :: input_data_id='{input_data_id}', input_data_name='{input_data['input_data_name']}'"
|
|
119
|
-
)
|
|
106
|
+
logger.debug(f"task_id='{task_id}' :: 入力データを削除しました。 :: input_data_id='{input_data_id}', input_data_name='{input_data['input_data_name']}'")
|
|
120
107
|
return True
|
|
121
108
|
|
|
122
109
|
def _should_delete_task(
|
|
@@ -138,10 +125,7 @@ class DeleteTaskMain(CommandLineWithConfirm):
|
|
|
138
125
|
logger.debug(f"{log_prefix} :: アノテーションが{len(annotation_list)}個付与されています。")
|
|
139
126
|
if not self.force: # noqa: SIM102
|
|
140
127
|
if len(annotation_list) > 0:
|
|
141
|
-
logger.info(
|
|
142
|
-
f"{log_prefix} :: アノテーションが付与されているため({len(annotation_list)}個)、タスクの削除をスキップします。"
|
|
143
|
-
f"削除するには`--force`を指定してください。"
|
|
144
|
-
)
|
|
128
|
+
logger.info(f"{log_prefix} :: アノテーションが付与されているため({len(annotation_list)}個)、タスクの削除をスキップします。削除するには`--force`を指定してください。")
|
|
145
129
|
return False
|
|
146
130
|
|
|
147
131
|
if not match_task_with_query(Task.from_dict(task), task_query):
|
|
@@ -170,7 +154,7 @@ class DeleteTaskMain(CommandLineWithConfirm):
|
|
|
170
154
|
True: タスクを削除した。False: タスクを削除しなかった。
|
|
171
155
|
|
|
172
156
|
"""
|
|
173
|
-
if task_index is not None:
|
|
157
|
+
if task_index is not None:
|
|
174
158
|
log_prefix = f"{task_index + 1} 件目, task_id='{task_id}'"
|
|
175
159
|
else:
|
|
176
160
|
log_prefix = f"task_id='{task_id}'"
|
|
@@ -295,9 +279,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
295
279
|
def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
|
|
296
280
|
subcommand_name = "delete"
|
|
297
281
|
subcommand_help = "タスクを削除します。"
|
|
298
|
-
description =
|
|
299
|
-
"タスクを削除します。ただし、作業中/完了状態のタスクは削除できません。デフォルトは、アノテーションが付与されているタスクは削除できません。"
|
|
300
|
-
)
|
|
282
|
+
description = "タスクを削除します。ただし、作業中/完了状態のタスクは削除できません。デフォルトは、アノテーションが付与されているタスクは削除できません。"
|
|
301
283
|
epilog = "オーナロールを持つユーザで実行してください。"
|
|
302
284
|
|
|
303
285
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description, epilog=epilog)
|
|
@@ -122,8 +122,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
122
122
|
parser.add_argument(
|
|
123
123
|
"--task_json",
|
|
124
124
|
type=Path,
|
|
125
|
-
help="タスク情報が記載されたJSONファイルのパスを指定すると、JSONに記載された情報を元にタスク一覧を出力します。\
|
|
126
|
-
"JSONファイルは ``$ annofabcli task download`` コマンドで取得できます。",
|
|
125
|
+
help="タスク情報が記載されたJSONファイルのパスを指定すると、JSONに記載された情報を元にタスク一覧を出力します。\nJSONファイルは ``$ annofabcli task download`` コマンドで取得できます。",
|
|
127
126
|
)
|
|
128
127
|
|
|
129
128
|
parser.add_argument(
|
|
@@ -139,7 +138,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
139
138
|
default=FormatArgument.CSV,
|
|
140
139
|
)
|
|
141
140
|
argument_parser.add_output()
|
|
142
|
-
argument_parser.add_csv_format()
|
|
143
141
|
|
|
144
142
|
parser.set_defaults(subcommand_func=main)
|
|
145
143
|
|
|
@@ -147,7 +145,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
147
145
|
def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
|
|
148
146
|
subcommand_name = "list_all"
|
|
149
147
|
subcommand_help = "すべてのタスクの一覧を出力します。"
|
|
150
|
-
description = "すべてのタスクの一覧を出力します。\n出力されるタスクは、コマンドを実行した日の02:00(JST)頃の状態です。最新の情報を出力したい場合は、 ``--latest`` を指定してください。"
|
|
148
|
+
description = "すべてのタスクの一覧を出力します。\n出力されるタスクは、コマンドを実行した日の02:00(JST)頃の状態です。最新の情報を出力したい場合は、 ``--latest`` を指定してください。"
|
|
151
149
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description=description)
|
|
152
150
|
parse_args(parser)
|
|
153
151
|
return parser
|
annofabcli/task/list_tasks.py
CHANGED
|
@@ -79,9 +79,7 @@ class ListTasksMain:
|
|
|
79
79
|
|
|
80
80
|
return task_query
|
|
81
81
|
|
|
82
|
-
def get_task_list_with_api(
|
|
83
|
-
self, project_id: str, task_query: Optional[dict[str, Any]] = None, user_id_list: Optional[list[str]] = None
|
|
84
|
-
) -> list[Task]:
|
|
82
|
+
def get_task_list_with_api(self, project_id: str, task_query: Optional[dict[str, Any]] = None, user_id_list: Optional[list[str]] = None) -> list[Task]:
|
|
85
83
|
"""
|
|
86
84
|
タスク一覧を取得する。
|
|
87
85
|
|
|
@@ -92,7 +90,7 @@ class ListTasksMain:
|
|
|
92
90
|
Returns:
|
|
93
91
|
対象の検査コメント一覧
|
|
94
92
|
"""
|
|
95
|
-
if task_query is not None:
|
|
93
|
+
if task_query is not None:
|
|
96
94
|
task_query = self._modify_task_query(project_id, task_query)
|
|
97
95
|
else:
|
|
98
96
|
task_query = {}
|
|
@@ -235,8 +233,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
235
233
|
"--task_id",
|
|
236
234
|
type=str,
|
|
237
235
|
nargs="+",
|
|
238
|
-
help="対象のタスクのtask_idを指定します。 ``--task_query`` 引数とは同時に指定できません。"
|
|
239
|
-
" ``file://`` を先頭に付けると、task_idの一覧が記載されたファイルを指定できます。",
|
|
236
|
+
help="対象のタスクのtask_idを指定します。 ``--task_query`` 引数とは同時に指定できません。 ``file://`` を先頭に付けると、task_idの一覧が記載されたファイルを指定できます。",
|
|
240
237
|
)
|
|
241
238
|
|
|
242
239
|
parser.add_argument(
|
|
@@ -252,7 +249,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
252
249
|
default=FormatArgument.CSV,
|
|
253
250
|
)
|
|
254
251
|
argument_parser.add_output()
|
|
255
|
-
argument_parser.add_csv_format()
|
|
256
252
|
|
|
257
253
|
parser.set_defaults(subcommand_func=main)
|
|
258
254
|
|
|
@@ -39,9 +39,7 @@ def get_post_rejection_annotation_worktime_hour(task_histories: list[TaskHistory
|
|
|
39
39
|
# 差し戻された履歴の直後で、教師付フェーズの作業時間を算出する
|
|
40
40
|
min_rejected_task_history_index = min(rejected_task_history_indices)
|
|
41
41
|
return sum(
|
|
42
|
-
isoduration_to_hour(history["accumulated_labor_time_milliseconds"])
|
|
43
|
-
for history in task_histories[min_rejected_task_history_index + 1 :]
|
|
44
|
-
if history["phase"] == TaskPhase.ANNOTATION.value
|
|
42
|
+
isoduration_to_hour(history["accumulated_labor_time_milliseconds"]) for history in task_histories[min_rejected_task_history_index + 1 :] if history["phase"] == TaskPhase.ANNOTATION.value
|
|
45
43
|
)
|
|
46
44
|
|
|
47
45
|
|
|
@@ -60,9 +58,7 @@ def get_post_rejection_inspection_worktime_hour(task_histories: list[TaskHistory
|
|
|
60
58
|
# 差し戻された履歴の直後で、検査フェーズの作業時間を算出する
|
|
61
59
|
min_rejected_task_history_index = min(rejected_task_history_indices)
|
|
62
60
|
return sum(
|
|
63
|
-
isoduration_to_hour(history["accumulated_labor_time_milliseconds"])
|
|
64
|
-
for history in task_histories[min_rejected_task_history_index + 1 :]
|
|
65
|
-
if history["phase"] == TaskPhase.INSPECTION.value
|
|
61
|
+
isoduration_to_hour(history["accumulated_labor_time_milliseconds"]) for history in task_histories[min_rejected_task_history_index + 1 :] if history["phase"] == TaskPhase.INSPECTION.value
|
|
66
62
|
)
|
|
67
63
|
|
|
68
64
|
|
|
@@ -104,10 +100,7 @@ def get_completed_datetime(task: dict[str, Any], task_histories: list[TaskHistor
|
|
|
104
100
|
"""
|
|
105
101
|
# 受入完了日時を設定
|
|
106
102
|
if task["phase"] == TaskPhase.ACCEPTANCE.value and task["status"] == TaskStatus.COMPLETE.value:
|
|
107
|
-
assert len(task_histories) > 0,
|
|
108
|
-
f"task_id='{task['task_id']}'のタスク履歴が0件です。参照しているタスク履歴情報が古い可能性があります。 "
|
|
109
|
-
f":: phase='{task['phase']}', status='{task['status']}'"
|
|
110
|
-
)
|
|
103
|
+
assert len(task_histories) > 0, f"task_id='{task['task_id']}'のタスク履歴が0件です。参照しているタスク履歴情報が古い可能性があります。 :: phase='{task['phase']}', status='{task['status']}'"
|
|
111
104
|
return task_histories[-1]["ended_datetime"]
|
|
112
105
|
else:
|
|
113
106
|
return None
|
|
@@ -175,7 +168,7 @@ def is_acceptance_phase_skipped(task_histories: list[TaskHistory]) -> bool:
|
|
|
175
168
|
return False
|
|
176
169
|
|
|
177
170
|
# スキップされた履歴より後に受入フェーズがなければ、受入がスキップされたタスクとみなす
|
|
178
|
-
# ただし、スキップされた履歴より後で、「アノテーション一覧で修正された」受入フェーズがある場合(account_id is None)は、スキップされた受入とみなす。
|
|
171
|
+
# ただし、スキップされた履歴より後で、「アノテーション一覧で修正された」受入フェーズがある場合(account_id is None)は、スキップされた受入とみなす。
|
|
179
172
|
last_task_history_index = task_history_index_list[-1]
|
|
180
173
|
return (
|
|
181
174
|
more_itertools.first_true(
|
|
@@ -212,11 +205,7 @@ def get_first_task_history(task_histories: list[TaskHistory], phase: TaskPhase)
|
|
|
212
205
|
最初のタスク履歴
|
|
213
206
|
"""
|
|
214
207
|
for history in task_histories:
|
|
215
|
-
if (
|
|
216
|
-
history["phase"] == phase.value
|
|
217
|
-
and history["account_id"] is not None
|
|
218
|
-
and isoduration_to_hour(history["accumulated_labor_time_milliseconds"]) > 0
|
|
219
|
-
):
|
|
208
|
+
if history["phase"] == phase.value and history["account_id"] is not None and isoduration_to_hour(history["accumulated_labor_time_milliseconds"]) > 0:
|
|
220
209
|
return history
|
|
221
210
|
return None
|
|
222
211
|
|
|
@@ -428,9 +417,7 @@ class TasksAddedTaskHistoryOutput:
|
|
|
428
417
|
]
|
|
429
418
|
|
|
430
419
|
task_history_columns = [
|
|
431
|
-
f"first_{phase.value}_{info}"
|
|
432
|
-
for phase in [TaskPhase.ANNOTATION, TaskPhase.INSPECTION, TaskPhase.ACCEPTANCE]
|
|
433
|
-
for info in ["user_id", "username", "started_datetime", "worktime_hour"]
|
|
420
|
+
f"first_{phase.value}_{info}" for phase in [TaskPhase.ANNOTATION, TaskPhase.INSPECTION, TaskPhase.ACCEPTANCE] for info in ["user_id", "username", "started_datetime", "worktime_hour"]
|
|
434
421
|
]
|
|
435
422
|
|
|
436
423
|
return (
|
|
@@ -505,8 +492,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
505
492
|
"--task_id",
|
|
506
493
|
type=str,
|
|
507
494
|
nargs="+",
|
|
508
|
-
help="対象のタスクのtask_idを指定します。 ``--task_query`` 引数とは同時に指定できません。"
|
|
509
|
-
" ``file://`` を先頭に付けると、task_idの一覧が記載されたファイルを指定できます。",
|
|
495
|
+
help="対象のタスクのtask_idを指定します。 ``--task_query`` 引数とは同時に指定できません。 ``file://`` を先頭に付けると、task_idの一覧が記載されたファイルを指定できます。",
|
|
510
496
|
)
|
|
511
497
|
|
|
512
498
|
argument_parser.add_output()
|
annofabcli/task/put_tasks.py
CHANGED
|
@@ -151,7 +151,7 @@ class PuttingTaskMain:
|
|
|
151
151
|
self.wait_for_completion(job["job_id"])
|
|
152
152
|
else:
|
|
153
153
|
logger.info(
|
|
154
|
-
f"以下のコマンドを実行すれば、タスク登録ジョブが終了するまで待ちます。 :: `annofabcli job wait --project_id {self.project_id} --job_type {job['job_type']} --job_id {job['job_id']}`"
|
|
154
|
+
f"以下のコマンドを実行すれば、タスク登録ジョブが終了するまで待ちます。 :: `annofabcli job wait --project_id {self.project_id} --job_type {job['job_type']} --job_id {job['job_id']}`"
|
|
155
155
|
)
|
|
156
156
|
|
|
157
157
|
def generate_task(
|
|
@@ -286,8 +286,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
286
286
|
"--api",
|
|
287
287
|
type=str,
|
|
288
288
|
choices=[e.value for e in ApiWithCreatingTask],
|
|
289
|
-
help="タスク作成に使うWebAPIを指定できます。 ``--csv`` or ``--json`` を指定したときのみ有効なオプションです。\n"
|
|
290
|
-
"未指定の場合は、作成するタスク数に応じて、適切なWebAPIを選択します。\n",
|
|
289
|
+
help="タスク作成に使うWebAPIを指定できます。 ``--csv`` or ``--json`` を指定したときのみ有効なオプションです。\n未指定の場合は、作成するタスク数に応じて、適切なWebAPIを選択します。\n",
|
|
291
290
|
)
|
|
292
291
|
|
|
293
292
|
parser.add_argument(
|
|
@@ -62,7 +62,7 @@ class PuttingTaskByCountMain:
|
|
|
62
62
|
self.wait_for_completion(job["job_id"])
|
|
63
63
|
else:
|
|
64
64
|
logger.info(
|
|
65
|
-
f"以下のコマンドを実行すれば、タスク登録ジョブが終了するまで待ちます。 :: `annofabcli job wait --project_id {self.project_id} --job_type {job['job_type']} --job_id {job['job_id']}`"
|
|
65
|
+
f"以下のコマンドを実行すれば、タスク登録ジョブが終了するまで待ちます。 :: `annofabcli job wait --project_id {self.project_id} --job_type {job['job_type']} --job_id {job['job_id']}`"
|
|
66
66
|
)
|
|
67
67
|
|
|
68
68
|
def wait_for_completion(self, job_id: str) -> None:
|
|
@@ -124,13 +124,9 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
124
124
|
|
|
125
125
|
parser.add_argument("--task_id_prefix", type=str, required=True, help="生成するタスクIDのプレフィックス")
|
|
126
126
|
|
|
127
|
-
parser.add_argument(
|
|
128
|
-
"--input_data_count", type=int, required=True, help="タスクに割り当てる入力データの個数。動画プロジェクトの場合は1を指定してください。"
|
|
129
|
-
)
|
|
127
|
+
parser.add_argument("--input_data_count", type=int, required=True, help="タスクに割り当てる入力データの個数。動画プロジェクトの場合は1を指定してください。")
|
|
130
128
|
|
|
131
|
-
parser.add_argument(
|
|
132
|
-
"--allow_duplicate_input_data", action="store_true", help="指定すると、既にタスクに使われている入力データを使ってタスクを作成します。"
|
|
133
|
-
)
|
|
129
|
+
parser.add_argument("--allow_duplicate_input_data", action="store_true", help="指定すると、既にタスクに使われている入力データを使ってタスクを作成します。")
|
|
134
130
|
|
|
135
131
|
parser.add_argument(
|
|
136
132
|
"--input_data_order",
|
annofabcli/task/reject_tasks.py
CHANGED
|
@@ -134,10 +134,7 @@ class RejectTasksMain(CommandLineWithConfirm):
|
|
|
134
134
|
return False
|
|
135
135
|
|
|
136
136
|
if task["status"] == TaskStatus.COMPLETE.value and not cancel_acceptance:
|
|
137
|
-
logger.warning(
|
|
138
|
-
f"task_id='{task_id}' :: タスクのstatusが'完了'なので、差し戻しできません。"
|
|
139
|
-
f"受入完了を取消す場合は、コマンドライン引数に'--cancel_acceptance'を追加してください。"
|
|
140
|
-
)
|
|
137
|
+
logger.warning(f"task_id='{task_id}' :: タスクのstatusが'完了'なので、差し戻しできません。受入完了を取消す場合は、コマンドライン引数に'--cancel_acceptance'を追加してください。")
|
|
141
138
|
return False
|
|
142
139
|
|
|
143
140
|
if not match_task_with_query(Task.from_dict(task), task_query):
|
|
@@ -194,9 +191,7 @@ class RejectTasksMain(CommandLineWithConfirm):
|
|
|
194
191
|
return False
|
|
195
192
|
|
|
196
193
|
if task["status"] == TaskStatus.COMPLETE.value and cancel_acceptance:
|
|
197
|
-
task = self.service.wrapper.cancel_completed_task(
|
|
198
|
-
project_id, task_id, operator_account_id=self.service.api.account_id, last_updated_datetime=task["updated_datetime"]
|
|
199
|
-
)
|
|
194
|
+
task = self.service.wrapper.cancel_completed_task(project_id, task_id, operator_account_id=self.service.api.account_id, last_updated_datetime=task["updated_datetime"])
|
|
200
195
|
logger.debug(f"{logging_prefix} :: task_id='{task_id}'のタスクに対して受入取消を実施(完了状態から未着手状態に変更)しました。")
|
|
201
196
|
|
|
202
197
|
try:
|
|
@@ -217,11 +212,7 @@ class RejectTasksMain(CommandLineWithConfirm):
|
|
|
217
212
|
return True
|
|
218
213
|
|
|
219
214
|
else:
|
|
220
|
-
assigned_annotator_account_id = (
|
|
221
|
-
self.facade.get_account_id_from_user_id(project_id, assigned_annotator_user_id)
|
|
222
|
-
if assigned_annotator_user_id is not None
|
|
223
|
-
else None
|
|
224
|
-
)
|
|
215
|
+
assigned_annotator_account_id = self.facade.get_account_id_from_user_id(project_id, assigned_annotator_user_id) if assigned_annotator_user_id is not None else None
|
|
225
216
|
|
|
226
217
|
self.service.wrapper.change_task_operator(project_id, task_id, operator_account_id=assigned_annotator_account_id)
|
|
227
218
|
|
|
@@ -403,7 +394,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
403
394
|
"-c",
|
|
404
395
|
"--comment",
|
|
405
396
|
type=str,
|
|
406
|
-
help="差し戻すときに付与する検査コメントを指定します。検査コメントはタスク内の先頭画像に付与します。付与する位置は ``--comment_data`` で指定できます。\n"
|
|
397
|
+
help="差し戻すときに付与する検査コメントを指定します。検査コメントはタスク内の先頭画像に付与します。付与する位置は ``--comment_data`` で指定できます。\n"
|
|
407
398
|
"未指定の場合は、検査コメントを付与せずに差し戻します。",
|
|
408
399
|
)
|
|
409
400
|
|
|
@@ -424,7 +415,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
424
415
|
"--custom_project_type",
|
|
425
416
|
type=str,
|
|
426
417
|
choices=[e.value for e in CustomProjectType],
|
|
427
|
-
help="[BETA] カスタムプロジェクトの種類を指定します。ビルトインのエディタプラグインを使用していないカスタムプロジェクトに対して、検査コメントの位置を指定しない場合は必須です。\n",
|
|
418
|
+
help="[BETA] カスタムプロジェクトの種類を指定します。ビルトインのエディタプラグインを使用していないカスタムプロジェクトに対して、検査コメントの位置を指定しない場合は必須です。\n",
|
|
428
419
|
)
|
|
429
420
|
|
|
430
421
|
# 差し戻したタスクの担当者の割当に関して
|
|
@@ -450,7 +441,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
450
441
|
"--parallelism",
|
|
451
442
|
type=int,
|
|
452
443
|
choices=PARALLELISM_CHOICES,
|
|
453
|
-
help="使用するプロセス数(並列度)を指定してください。指定する場合は必ず ``--yes`` を指定してください。指定しない場合は、逐次的に処理します。",
|
|
444
|
+
help="使用するプロセス数(並列度)を指定してください。指定する場合は必ず ``--yes`` を指定してください。指定しない場合は、逐次的に処理します。",
|
|
454
445
|
)
|
|
455
446
|
|
|
456
447
|
parser.set_defaults(subcommand_func=main)
|
|
@@ -460,10 +451,7 @@ def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argpa
|
|
|
460
451
|
subcommand_name = "reject"
|
|
461
452
|
subcommand_help = "タスクを差し戻します。"
|
|
462
453
|
description = "タスクを差し戻します。差し戻す際、検査コメントを付与することもできます。作業中状態のタスクに対しては差し戻せません。"
|
|
463
|
-
epilog =
|
|
464
|
-
"オーナロールを持つユーザで実行してください。"
|
|
465
|
-
"``--cancel_acceptance`` を指定していない AND ``--comment`` を指定している場合は、チェッカーロールを持つユーザーも実行できます。"
|
|
466
|
-
)
|
|
454
|
+
epilog = "オーナロールを持つユーザで実行してください。``--cancel_acceptance`` を指定していない AND ``--comment`` を指定している場合は、チェッカーロールを持つユーザーも実行できます。"
|
|
467
455
|
|
|
468
456
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description, epilog=epilog)
|
|
469
457
|
parse_args(parser)
|
|
@@ -74,7 +74,7 @@ class UpdateMetadataOfTaskMain(CommandLineWithConfirm):
|
|
|
74
74
|
if not self.confirm_processing(self.get_confirm_message(task_id, metadata)):
|
|
75
75
|
return False
|
|
76
76
|
|
|
77
|
-
if self.is_overwrite_metadata:
|
|
77
|
+
if self.is_overwrite_metadata:
|
|
78
78
|
new_metadata = metadata
|
|
79
79
|
else:
|
|
80
80
|
new_metadata = {**task["metadata"], **metadata}
|
|
@@ -266,7 +266,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
266
266
|
"--parallelism",
|
|
267
267
|
type=int,
|
|
268
268
|
choices=PARALLELISM_CHOICES,
|
|
269
|
-
help="使用するプロセス数(並列度)を指定してください。指定する場合は必ず ``--yes`` を指定してください。指定しない場合は、逐次的に処理します。",
|
|
269
|
+
help="使用するプロセス数(並列度)を指定してください。指定する場合は必ず ``--yes`` を指定してください。指定しない場合は、逐次的に処理します。",
|
|
270
270
|
)
|
|
271
271
|
|
|
272
272
|
parser.set_defaults(subcommand_func=main)
|
|
@@ -40,9 +40,7 @@ class ListTaskHistoryWithJsonMain:
|
|
|
40
40
|
filtered_task_history_dict[task_id] = task_history_list
|
|
41
41
|
return filtered_task_history_dict
|
|
42
42
|
|
|
43
|
-
def get_task_history_dict(
|
|
44
|
-
self, project_id: str, task_history_json: Optional[Path] = None, task_id_list: Optional[list[str]] = None
|
|
45
|
-
) -> TaskHistoryDict:
|
|
43
|
+
def get_task_history_dict(self, project_id: str, task_history_json: Optional[Path] = None, task_id_list: Optional[list[str]] = None) -> TaskHistoryDict:
|
|
46
44
|
"""出力対象のタスク履歴情報を取得する"""
|
|
47
45
|
if task_history_json is None:
|
|
48
46
|
downloading_obj = DownloadingFile(self.service)
|
|
@@ -149,7 +147,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
149
147
|
default=FormatArgument.CSV,
|
|
150
148
|
)
|
|
151
149
|
argument_parser.add_output()
|
|
152
|
-
argument_parser.add_csv_format()
|
|
153
150
|
|
|
154
151
|
parser.set_defaults(subcommand_func=main)
|
|
155
152
|
|
|
@@ -159,7 +156,7 @@ def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argpa
|
|
|
159
156
|
subcommand_help = "すべてのタスク履歴の一覧を出力します。"
|
|
160
157
|
description = (
|
|
161
158
|
"すべてのタスク履歴の一覧を出力します。\n"
|
|
162
|
-
"出力されるタスク履歴は、コマンドを実行した日の02:00(JST)頃の状態です。最新の情報を出力したい場合は、 ``annofabcli task_history list`` コマンドを実行してください。"
|
|
159
|
+
"出力されるタスク履歴は、コマンドを実行した日の02:00(JST)頃の状態です。最新の情報を出力したい場合は、 ``annofabcli task_history list`` コマンドを実行してください。"
|
|
163
160
|
)
|
|
164
161
|
|
|
165
162
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
|
|
@@ -31,9 +31,7 @@ class ListTaskHistoryEventWithJsonMain:
|
|
|
31
31
|
self.service = service
|
|
32
32
|
|
|
33
33
|
@staticmethod
|
|
34
|
-
def filter_task_history_event(
|
|
35
|
-
task_history_event_list: list[TaskHistoryEvent], task_id_list: Optional[list[str]] = None
|
|
36
|
-
) -> list[TaskHistoryEvent]:
|
|
34
|
+
def filter_task_history_event(task_history_event_list: list[TaskHistoryEvent], task_id_list: Optional[list[str]] = None) -> list[TaskHistoryEvent]:
|
|
37
35
|
if task_id_list is not None:
|
|
38
36
|
result = []
|
|
39
37
|
task_id_set = set(task_id_list)
|
|
@@ -45,9 +43,7 @@ class ListTaskHistoryEventWithJsonMain:
|
|
|
45
43
|
|
|
46
44
|
return task_history_event_list
|
|
47
45
|
|
|
48
|
-
def get_task_history_event_list(
|
|
49
|
-
self, project_id: str, task_history_event_json: Optional[Path] = None, task_id_list: Optional[list[str]] = None
|
|
50
|
-
) -> list[dict[str, Any]]:
|
|
46
|
+
def get_task_history_event_list(self, project_id: str, task_history_event_json: Optional[Path] = None, task_id_list: Optional[list[str]] = None) -> list[dict[str, Any]]:
|
|
51
47
|
if task_history_event_json is None:
|
|
52
48
|
downloading_obj = DownloadingFile(self.service)
|
|
53
49
|
# `NamedTemporaryFile`を使わない理由: Windowsで`PermissionError`が発生するため
|
|
@@ -83,9 +79,7 @@ class ListTaskHistoryEventWithJson(CommandLine):
|
|
|
83
79
|
super().validate_project(project_id, project_member_roles=None)
|
|
84
80
|
|
|
85
81
|
main_obj = ListTaskHistoryEventWithJsonMain(self.service)
|
|
86
|
-
task_history_event_list = main_obj.get_task_history_event_list(
|
|
87
|
-
project_id, task_history_event_json=task_history_event_json, task_id_list=task_id_list
|
|
88
|
-
)
|
|
82
|
+
task_history_event_list = main_obj.get_task_history_event_list(project_id, task_history_event_json=task_history_event_json, task_id_list=task_id_list)
|
|
89
83
|
|
|
90
84
|
logger.debug(f"タスク履歴イベント一覧の件数: {len(task_history_event_list)}")
|
|
91
85
|
|
|
@@ -149,7 +143,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
149
143
|
default=FormatArgument.CSV,
|
|
150
144
|
)
|
|
151
145
|
argument_parser.add_output()
|
|
152
|
-
argument_parser.add_csv_format()
|
|
153
146
|
|
|
154
147
|
parser.set_defaults(subcommand_func=main)
|
|
155
148
|
|
|
@@ -157,7 +150,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
157
150
|
def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
|
|
158
151
|
subcommand_name = "list_all"
|
|
159
152
|
subcommand_help = "すべてのタスク履歴イベントの一覧を出力します。"
|
|
160
|
-
description = "すべてのタスク履歴イベントの一覧を出力します。\n出力されるタスク履歴イベントは、コマンドを実行した日の02:00(JST)頃の状態です。最新の情報を出力する方法はありません。"
|
|
153
|
+
description = "すべてのタスク履歴イベントの一覧を出力します。\n出力されるタスク履歴イベントは、コマンドを実行した日の02:00(JST)頃の状態です。最新の情報を出力する方法はありません。"
|
|
161
154
|
|
|
162
155
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
|
|
163
156
|
parse_args(parser)
|
|
@@ -56,9 +56,7 @@ class ListWorktimeFromTaskHistoryEventMain:
|
|
|
56
56
|
self.visualize = AddProps(service, project_id)
|
|
57
57
|
|
|
58
58
|
@staticmethod
|
|
59
|
-
def filter_task_history_event(
|
|
60
|
-
task_history_event_list: list[TaskHistoryEvent], task_id_list: Optional[list[str]] = None
|
|
61
|
-
) -> list[TaskHistoryEvent]:
|
|
59
|
+
def filter_task_history_event(task_history_event_list: list[TaskHistoryEvent], task_id_list: Optional[list[str]] = None) -> list[TaskHistoryEvent]:
|
|
62
60
|
if task_id_list is not None:
|
|
63
61
|
result = []
|
|
64
62
|
task_id_set = set(task_id_list)
|
|
@@ -115,11 +113,7 @@ class ListWorktimeFromTaskHistoryEventMain:
|
|
|
115
113
|
def _create_worktime(self, start_event: TaskHistoryEvent, end_event: TaskHistoryEvent) -> WorktimeFromTaskHistoryEvent:
|
|
116
114
|
diff = parse(end_event["created_datetime"]) - parse(start_event["created_datetime"])
|
|
117
115
|
worktime_hour = diff.total_seconds() / 3600
|
|
118
|
-
assert worktime_hour >= 0,
|
|
119
|
-
f"worktime_hourが負の値です。"
|
|
120
|
-
f"start_event.created_datetime={start_event['created_datetime']}, "
|
|
121
|
-
f"end_event.created_datetime{end_event['created_datetime']}"
|
|
122
|
-
)
|
|
116
|
+
assert worktime_hour >= 0, f"worktime_hourが負の値です。start_event.created_datetime={start_event['created_datetime']}, end_event.created_datetime{end_event['created_datetime']}"
|
|
123
117
|
|
|
124
118
|
member = self.visualize.get_project_member_from_account_id(start_event["account_id"])
|
|
125
119
|
if member is not None:
|
|
@@ -163,7 +157,7 @@ class ListWorktimeFromTaskHistoryEventMain:
|
|
|
163
157
|
while i < len(task_history_event_list):
|
|
164
158
|
event = task_history_event_list[i]
|
|
165
159
|
# account_idを判定している理由:
|
|
166
|
-
# 受入完了状態のタスクで作成されたアノテーションを、アノテーション一覧画面からオーナーが一括編集すると、account_idがnullのタスク履歴イベントが生成されるため
|
|
160
|
+
# 受入完了状態のタスクで作成されたアノテーションを、アノテーション一覧画面からオーナーが一括編集すると、account_idがnullのタスク履歴イベントが生成されるため
|
|
167
161
|
if event["status"] != TaskStatus.WORKING.value or event["account_id"] is None:
|
|
168
162
|
i += 1
|
|
169
163
|
continue
|
|
@@ -180,10 +174,7 @@ class ListWorktimeFromTaskHistoryEventMain:
|
|
|
180
174
|
TaskStatus.ON_HOLD.value,
|
|
181
175
|
TaskStatus.COMPLETE.value,
|
|
182
176
|
}:
|
|
183
|
-
logger.warning(
|
|
184
|
-
"作業中状態のタスク履歴イベントに対応するタスク履歴イベントが存在しませんでした。"
|
|
185
|
-
f":: start_event={start_event}, next_event={next_event}"
|
|
186
|
-
)
|
|
177
|
+
logger.warning(f"作業中状態のタスク履歴イベントに対応するタスク履歴イベントが存在しませんでした。:: start_event={start_event}, next_event={next_event}")
|
|
187
178
|
i += 1
|
|
188
179
|
continue
|
|
189
180
|
|
|
@@ -312,7 +303,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
312
303
|
default=FormatArgument.CSV,
|
|
313
304
|
)
|
|
314
305
|
argument_parser.add_output()
|
|
315
|
-
argument_parser.add_csv_format()
|
|
316
306
|
|
|
317
307
|
parser.set_defaults(subcommand_func=main)
|
|
318
308
|
|