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
|
@@ -31,9 +31,7 @@ from annofabcli.common.facade import AnnofabApiFacade
|
|
|
31
31
|
logger = logging.getLogger(__name__)
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def remove_overlap_of_binary_image_array(
|
|
35
|
-
binary_image_array_by_annotation: dict[str, numpy.ndarray], annotation_id_list: list[str]
|
|
36
|
-
) -> dict[str, numpy.ndarray]:
|
|
34
|
+
def remove_overlap_of_binary_image_array(binary_image_array_by_annotation: dict[str, numpy.ndarray], annotation_id_list: list[str]) -> dict[str, numpy.ndarray]:
|
|
37
35
|
"""
|
|
38
36
|
塗りつぶし画像の重なりを除去したbool配列をdictで返します。
|
|
39
37
|
|
|
@@ -99,9 +97,7 @@ class RemoveSegmentationOverlapMain(CommandLineWithConfirm):
|
|
|
99
97
|
|
|
100
98
|
# reversedを使っている理由:
|
|
101
99
|
# `details`には、前面から背面の順にアノテーションが格納されているため、
|
|
102
|
-
output_binary_image_array_by_annotation = remove_overlap_of_binary_image_array(
|
|
103
|
-
input_binary_image_array_by_annotation, list(reversed(segmentation_annotation_id_list))
|
|
104
|
-
)
|
|
100
|
+
output_binary_image_array_by_annotation = remove_overlap_of_binary_image_array(input_binary_image_array_by_annotation, list(reversed(segmentation_annotation_id_list)))
|
|
105
101
|
|
|
106
102
|
updated_annotation_id_list = []
|
|
107
103
|
for annotation_id, output_binary_image_array in output_binary_image_array_by_annotation.items():
|
|
@@ -128,10 +124,7 @@ class RemoveSegmentationOverlapMain(CommandLineWithConfirm):
|
|
|
128
124
|
temp_dir_path = Path(temp_dir)
|
|
129
125
|
updated_annotation_id_list = self.remove_segmentation_overlap_and_save(old_details, temp_dir_path)
|
|
130
126
|
if len(updated_annotation_id_list) == 0:
|
|
131
|
-
logger.debug(
|
|
132
|
-
f"{log_message_prefix}塗りつぶしアノテーションの重なりはなかったので、スキップします。 :: "
|
|
133
|
-
f"task_id='{task_id}', input_data_id='{input_data_id}'"
|
|
134
|
-
)
|
|
127
|
+
logger.debug(f"{log_message_prefix}塗りつぶしアノテーションの重なりはなかったので、スキップします。 :: task_id='{task_id}', input_data_id='{input_data_id}'")
|
|
135
128
|
return False
|
|
136
129
|
|
|
137
130
|
logger.debug(
|
|
@@ -164,10 +157,7 @@ class RemoveSegmentationOverlapMain(CommandLineWithConfirm):
|
|
|
164
157
|
"updated_datetime": old_annotation["updated_datetime"],
|
|
165
158
|
}
|
|
166
159
|
self.annofab_service.api.put_annotation(self.project_id, task_id, input_data_id, query_params={"v": "2"}, request_body=request_body)
|
|
167
|
-
logger.debug(
|
|
168
|
-
f"{log_message_prefix}{len(updated_annotation_id_list)} 件の塗りつぶしアノテーションを更新しました。 :: "
|
|
169
|
-
f"task_id='{task_id}', input_data_id='{input_data_id}'"
|
|
170
|
-
)
|
|
160
|
+
logger.debug(f"{log_message_prefix}{len(updated_annotation_id_list)} 件の塗りつぶしアノテーションを更新しました。 :: task_id='{task_id}', input_data_id='{input_data_id}'")
|
|
171
161
|
return True
|
|
172
162
|
|
|
173
163
|
def update_segmentation_annotation_for_task(self, task_id: str, *, task_index: Optional[int] = None) -> int:
|
|
@@ -185,10 +175,7 @@ class RemoveSegmentationOverlapMain(CommandLineWithConfirm):
|
|
|
185
175
|
return 0
|
|
186
176
|
|
|
187
177
|
if task["status"] in {TaskStatus.WORKING.value, TaskStatus.COMPLETE.value}:
|
|
188
|
-
logger.debug(
|
|
189
|
-
f"{log_message_prefix}task_id='{task_id}'のタスクの状態は「作業中」または「完了」であるため、"
|
|
190
|
-
f"アノテーションの更新をスキップします。 :: status='{task['status']}'"
|
|
191
|
-
)
|
|
178
|
+
logger.debug(f"{log_message_prefix}task_id='{task_id}'のタスクの状態は「作業中」または「完了」であるため、アノテーションの更新をスキップします。 :: status='{task['status']}'")
|
|
192
179
|
return 0
|
|
193
180
|
|
|
194
181
|
if not self.confirm_processing(f"task_id='{task_id}'の塗りつぶしアノテーションの重なりを除去しますか?"):
|
|
@@ -222,16 +209,12 @@ class RemoveSegmentationOverlapMain(CommandLineWithConfirm):
|
|
|
222
209
|
if result:
|
|
223
210
|
success_input_data_count += 1
|
|
224
211
|
except Exception:
|
|
225
|
-
logger.warning(
|
|
226
|
-
f"{log_message_prefix}task_id='{task_id}', input_data_id='{input_data_id}'のアノテーションの更新に失敗しました。", exc_info=True
|
|
227
|
-
)
|
|
212
|
+
logger.warning(f"{log_message_prefix}task_id='{task_id}', input_data_id='{input_data_id}'のアノテーションの更新に失敗しました。", exc_info=True)
|
|
228
213
|
continue
|
|
229
214
|
|
|
230
215
|
# 担当者を元に戻す
|
|
231
216
|
if changed_operator:
|
|
232
|
-
logger.debug(
|
|
233
|
-
f"{log_message_prefix}task_id='{task_id}' のタスクの担当者を、元の担当者(account_id='{original_operator_account_id}')に変更します。"
|
|
234
|
-
)
|
|
217
|
+
logger.debug(f"{log_message_prefix}task_id='{task_id}' のタスクの担当者を、元の担当者(account_id='{original_operator_account_id}')に変更します。")
|
|
235
218
|
self.annofab_service.wrapper.change_task_operator(
|
|
236
219
|
self.project_id,
|
|
237
220
|
task_id,
|
|
@@ -337,11 +320,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
337
320
|
def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
|
|
338
321
|
subcommand_name = "remove_segmentation_overlap"
|
|
339
322
|
subcommand_help = "塗りつぶしアノテーションの重なりを除去します。"
|
|
340
|
-
description =
|
|
341
|
-
"塗りつぶしアノテーションの重なりを除去します。"
|
|
342
|
-
"Annofabでインスタンスセグメンテーションは重ねることができてしまいます。"
|
|
343
|
-
"この重なりをなくしたいときに有用です。"
|
|
344
|
-
)
|
|
323
|
+
description = "塗りつぶしアノテーションの重なりを除去します。Annofabでインスタンスセグメンテーションは重ねることができてしまいます。この重なりをなくしたいときに有用です。"
|
|
345
324
|
epilog = "オーナー、チェッカーまたはアノテータロールを持つユーザで実行してください。"
|
|
346
325
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description, epilog=epilog)
|
|
347
326
|
parse_args(parser)
|
|
@@ -214,9 +214,7 @@ class RestoreAnnotationMain(CommandLineWithConfirm):
|
|
|
214
214
|
parallelism: 並列度。Noneなら逐次処理
|
|
215
215
|
"""
|
|
216
216
|
|
|
217
|
-
def get_iter_task_parser_from_task_ids(
|
|
218
|
-
_iter_task_parser: Iterator[SimpleAnnotationParserByTask], _target_task_ids: set[str]
|
|
219
|
-
) -> Iterator[SimpleAnnotationParserByTask]:
|
|
217
|
+
def get_iter_task_parser_from_task_ids(_iter_task_parser: Iterator[SimpleAnnotationParserByTask], _target_task_ids: set[str]) -> Iterator[SimpleAnnotationParserByTask]:
|
|
220
218
|
for task_parser in _iter_task_parser:
|
|
221
219
|
if task_parser.task_id in _target_task_ids:
|
|
222
220
|
_target_task_ids.remove(task_parser.task_id)
|
|
@@ -252,9 +250,7 @@ class RestoreAnnotationMain(CommandLineWithConfirm):
|
|
|
252
250
|
task_count += 1
|
|
253
251
|
|
|
254
252
|
if target_task_ids is not None and len(tmp_target_task_ids) > 0:
|
|
255
|
-
logger.warning(
|
|
256
|
-
f"'--task_id'で指定したタスクの内 {len(tmp_target_task_ids)} 件は、リストア対象のアノテーションデータに含まれていません。 :: {tmp_target_task_ids}" # noqa: E501
|
|
257
|
-
)
|
|
253
|
+
logger.warning(f"'--task_id'で指定したタスクの内 {len(tmp_target_task_ids)} 件は、リストア対象のアノテーションデータに含まれていません。 :: {tmp_target_task_ids}")
|
|
258
254
|
|
|
259
255
|
logger.info(f"{success_count} / {task_count} 件のタスクに対してアノテーションをリストアしました。")
|
|
260
256
|
|
|
@@ -288,9 +284,7 @@ class RestoreAnnotation(CommandLine):
|
|
|
288
284
|
|
|
289
285
|
task_id_list = set(annofabcli.common.cli.get_list_from_args(args.task_id)) if args.task_id is not None else None
|
|
290
286
|
|
|
291
|
-
RestoreAnnotationMain(self.service, project_id=project_id, is_force=args.force, all_yes=args.yes).main(
|
|
292
|
-
args.annotation, target_task_ids=task_id_list, parallelism=args.parallelism
|
|
293
|
-
)
|
|
287
|
+
RestoreAnnotationMain(self.service, project_id=project_id, is_force=args.force, all_yes=args.yes).main(args.annotation, target_task_ids=task_id_list, parallelism=args.parallelism)
|
|
294
288
|
|
|
295
289
|
|
|
296
290
|
def main(args: argparse.Namespace) -> None:
|
|
@@ -60,10 +60,7 @@ class AddAttributeRestrictionMain(CommandLineWithConfirm):
|
|
|
60
60
|
try:
|
|
61
61
|
restriction_text = msg_obj.get_restriction_text(restriction["additional_data_definition_id"], restriction["condition"])
|
|
62
62
|
except ValueError as e:
|
|
63
|
-
logger.warning(
|
|
64
|
-
f"{index + 1}件目 :: 次の属性制約は存在しないIDが含まれていたため、アノテーション仕様に追加しません。 :: "
|
|
65
|
-
f"restriction=`{restriction}`, error_message=`{e!s}`"
|
|
66
|
-
)
|
|
63
|
+
logger.warning(f"{index + 1}件目 :: 次の属性制約は存在しないIDが含まれていたため、アノテーション仕様に追加しません。 :: restriction=`{restriction}`, error_message=`{e!s}`")
|
|
67
64
|
continue
|
|
68
65
|
|
|
69
66
|
if restriction in old_restrictions:
|
|
@@ -131,10 +128,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
131
128
|
"--json",
|
|
132
129
|
type=str,
|
|
133
130
|
required=True,
|
|
134
|
-
help="追加する属性の制約情報のJSONを指定します。"
|
|
135
|
-
"JSON形式は ... を参照してください。\n"
|
|
136
|
-
f"(例) ``{json.dumps(sample_json)}``\n"
|
|
137
|
-
"``file://`` を先頭に付けるとjsonファイルを指定できます。",
|
|
131
|
+
help=f"追加する属性の制約情報のJSONを指定します。JSON形式は ... を参照してください。\n(例) ``{json.dumps(sample_json)}``\n``file://`` を先頭に付けるとjsonファイルを指定できます。",
|
|
138
132
|
)
|
|
139
133
|
|
|
140
134
|
parser.add_argument("--comment", type=str, help="アノテーション仕様の変更時に指定できるコメント。未指定の場合、自動でコメントが生成されます。")
|
|
@@ -169,11 +169,7 @@ class AttributeRestrictionMessage:
|
|
|
169
169
|
return tmp
|
|
170
170
|
|
|
171
171
|
def get_attribute_from_name(self, attribute_name: str) -> Optional[dict[str, Any]]:
|
|
172
|
-
tmp = [
|
|
173
|
-
attribute
|
|
174
|
-
for attribute in self.attribute_dict.values()
|
|
175
|
-
if AnnofabApiFacade.get_additional_data_definition_name_en(attribute) == attribute_name
|
|
176
|
-
]
|
|
172
|
+
tmp = [attribute for attribute in self.attribute_dict.values() if AnnofabApiFacade.get_additional_data_definition_name_en(attribute) == attribute_name]
|
|
177
173
|
if len(tmp) == 1:
|
|
178
174
|
return tmp[0]
|
|
179
175
|
elif len(tmp) == 0:
|
|
@@ -231,10 +227,6 @@ class AttributeRestrictionMessage:
|
|
|
231
227
|
"""
|
|
232
228
|
if target_attribute_names is not None or target_label_names is not None:
|
|
233
229
|
target_attribute_ids = self.get_target_attribute_ids(target_attribute_names=target_attribute_names, target_label_names=target_label_names)
|
|
234
|
-
return [
|
|
235
|
-
self.get_restriction_text(e["additional_data_definition_id"], e["condition"])
|
|
236
|
-
for e in restrictions
|
|
237
|
-
if e["additional_data_definition_id"] in target_attribute_ids
|
|
238
|
-
]
|
|
230
|
+
return [self.get_restriction_text(e["additional_data_definition_id"], e["condition"]) for e in restrictions if e["additional_data_definition_id"] in target_attribute_ids]
|
|
239
231
|
else:
|
|
240
232
|
return [self.get_restriction_text(e["additional_data_definition_id"], e["condition"]) for e in restrictions]
|
|
@@ -28,9 +28,7 @@ class ExportAnnotationSpecs(CommandLine):
|
|
|
28
28
|
sorted_histories = sorted(histories, key=lambda x: x["updated_datetime"], reverse=True)
|
|
29
29
|
|
|
30
30
|
if before + 1 > len(sorted_histories):
|
|
31
|
-
logger.warning(
|
|
32
|
-
f"アノテーション仕様の履歴は{len(sorted_histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。"
|
|
33
|
-
)
|
|
31
|
+
logger.warning(f"アノテーション仕様の履歴は{len(sorted_histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。")
|
|
34
32
|
return None
|
|
35
33
|
|
|
36
34
|
history = sorted_histories[before]
|
|
@@ -101,16 +101,11 @@ class ReplacingAttributeId(CommandLineWithConfirm):
|
|
|
101
101
|
continue
|
|
102
102
|
|
|
103
103
|
if not self.validate_attribute_id(attribute_name_en):
|
|
104
|
-
logger.warning(
|
|
105
|
-
f"属性英語名='{attribute_name_en}'は属性IDに利用できない文字を含むため、"
|
|
106
|
-
f"属性ID='{attribute_id}'を'{attribute_name_en}'に変更しません。"
|
|
107
|
-
)
|
|
104
|
+
logger.warning(f"属性英語名='{attribute_name_en}'は属性IDに利用できない文字を含むため、属性ID='{attribute_id}'を'{attribute_name_en}'に変更しません。")
|
|
108
105
|
continue
|
|
109
106
|
|
|
110
107
|
if self.exists_attribute_with_attribute_id(attribute_list, attribute_id=attribute_name_en):
|
|
111
|
-
logger.warning(
|
|
112
|
-
f"属性ID='{attribute_name_en}'である属性が既に存在するため、属性ID='{attribute_id}'を'{attribute_name_en}'に変更しません。"
|
|
113
|
-
)
|
|
108
|
+
logger.warning(f"属性ID='{attribute_name_en}'である属性が既に存在するため、属性ID='{attribute_id}'を'{attribute_name_en}'に変更しません。")
|
|
114
109
|
continue
|
|
115
110
|
|
|
116
111
|
if not self.confirm_processing(f"属性ID='{attribute_id}'を'{attribute_name_en}'に変更したアノテーション仕様のJSONを出力しますか?"):
|
|
@@ -118,9 +113,7 @@ class ReplacingAttributeId(CommandLineWithConfirm):
|
|
|
118
113
|
|
|
119
114
|
attribute["additional_data_definition_id"] = attribute_name_en
|
|
120
115
|
self.replace_attribute_id_of_labels(old_attribute_id=attribute_id, new_attribute_id=attribute_name_en, label_list=label_list)
|
|
121
|
-
self.replace_attribute_id_of_restrictions(
|
|
122
|
-
old_attribute_id=attribute_id, new_attribute_id=attribute_name_en, restriction_list=restriction_list
|
|
123
|
-
)
|
|
116
|
+
self.replace_attribute_id_of_restrictions(old_attribute_id=attribute_id, new_attribute_id=attribute_name_en, restriction_list=restriction_list)
|
|
124
117
|
replaced_count += 1
|
|
125
118
|
|
|
126
119
|
logger.info(f"{replaced_count} 個の属性の属性IDを変更しました。")
|
|
@@ -44,7 +44,7 @@ class ReplacingChoiceId(CommandLineWithConfirm):
|
|
|
44
44
|
annotation_specs: (IN/OUT) アノテーション仕様情報。中身が変更されます。
|
|
45
45
|
target_attribute_names: 変更対象のラジオボタン/ドロップダウン属性の英語名。Noneならすべてのラジオボタン/ドロップダウン属性の選択肢IDを変更します。
|
|
46
46
|
|
|
47
|
-
"""
|
|
47
|
+
"""
|
|
48
48
|
attribute_list = annotation_specs["additionals"]
|
|
49
49
|
|
|
50
50
|
replaced_count = 0
|
|
@@ -62,9 +62,7 @@ class ReplacingChoiceId(CommandLineWithConfirm):
|
|
|
62
62
|
|
|
63
63
|
choice_list = attribute["choices"]
|
|
64
64
|
|
|
65
|
-
if not self.confirm_processing(
|
|
66
|
-
f"属性英語名='{attribute_name_en}'の{len(choice_list)}個の選択肢IDを、選択肢英語名に変更したアノテーション仕様のJSONを出力しますか?"
|
|
67
|
-
):
|
|
65
|
+
if not self.confirm_processing(f"属性英語名='{attribute_name_en}'の{len(choice_list)}個の選択肢IDを、選択肢英語名に変更したアノテーション仕様のJSONを出力しますか?"):
|
|
68
66
|
continue
|
|
69
67
|
|
|
70
68
|
replaced_choice_id_count = 0
|
|
@@ -74,16 +72,12 @@ class ReplacingChoiceId(CommandLineWithConfirm):
|
|
|
74
72
|
|
|
75
73
|
if not self.validate_choice_id(choice_name_en):
|
|
76
74
|
logger.warning(
|
|
77
|
-
f"属性英語名='{attribute_name_en}', 選択肢英語名='{choice_name_en}'は選択肢ID
|
|
78
|
-
f"選択肢ID='{choice_id}'を'{choice_name_en}'に変更しません。"
|
|
75
|
+
f"属性英語名='{attribute_name_en}', 選択肢英語名='{choice_name_en}'は選択肢IDに利用できない文字を含むため、選択肢ID='{choice_id}'を'{choice_name_en}'に変更しません。"
|
|
79
76
|
)
|
|
80
77
|
continue
|
|
81
78
|
|
|
82
79
|
if self.exists_choice_with_choice_id(choice_list, choice_id=choice_name_en):
|
|
83
|
-
logger.warning(
|
|
84
|
-
f"属性英語名='{attribute_name_en}', 選択肢ID='{choice_name_en}'である選択肢が既に存在するため、"
|
|
85
|
-
f"選択肢ID='{choice_id}'を'{choice_name_en}'に変更しません。"
|
|
86
|
-
)
|
|
80
|
+
logger.warning(f"属性英語名='{attribute_name_en}', 選択肢ID='{choice_name_en}'である選択肢が既に存在するため、選択肢ID='{choice_id}'を'{choice_name_en}'に変更しません。")
|
|
87
81
|
continue
|
|
88
82
|
|
|
89
83
|
choice["choice_id"] = choice_name_en
|
|
@@ -86,9 +86,7 @@ class ReplacingLabelId(CommandLineWithConfirm):
|
|
|
86
86
|
continue
|
|
87
87
|
|
|
88
88
|
if not self.validate_label_id(label_name_en):
|
|
89
|
-
logger.warning(
|
|
90
|
-
f"label_name_en='{label_name_en}'はlabel_idにできない文字を含むため、label_id='{label_id}'を'{label_name_en}'に変更しません。"
|
|
91
|
-
)
|
|
89
|
+
logger.warning(f"label_name_en='{label_name_en}'はlabel_idにできない文字を含むため、label_id='{label_id}'を'{label_name_en}'に変更しません。")
|
|
92
90
|
continue
|
|
93
91
|
|
|
94
92
|
if self.exists_label_with_label_id(label_list, label_id=label_name_en):
|
|
@@ -43,7 +43,7 @@ class FlattenAttribute(DataClassJsonMixin):
|
|
|
43
43
|
Notes:
|
|
44
44
|
APIレスポンスの ``additional_data_definition_id`` に相当します。
|
|
45
45
|
``additional_data_definition_id`` という名前がアノテーションJSONの `attributes` と対応していることが分かりにくかったので、`attribute_id`という名前に変えました。
|
|
46
|
-
"""
|
|
46
|
+
"""
|
|
47
47
|
attribute_name_en: Optional[str]
|
|
48
48
|
attribute_name_ja: Optional[str]
|
|
49
49
|
attribute_name_vi: Optional[str]
|
|
@@ -81,9 +81,7 @@ def create_relationship_between_attribute_and_label(labels_v3: list[dict[str, An
|
|
|
81
81
|
return result
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
def create_flatten_attribute_list_from_additionals(
|
|
85
|
-
additionals_v3: list[dict[str, Any]], labels_v3: list[dict[str, Any]], restrictions: list[dict[str, Any]]
|
|
86
|
-
) -> list[FlattenAttribute]:
|
|
84
|
+
def create_flatten_attribute_list_from_additionals(additionals_v3: list[dict[str, Any]], labels_v3: list[dict[str, Any]], restrictions: list[dict[str, Any]]) -> list[FlattenAttribute]:
|
|
87
85
|
"""
|
|
88
86
|
APIから取得した属性情報(v3版)から、属性情報の一覧を生成します。
|
|
89
87
|
|
|
@@ -127,12 +125,8 @@ def create_flatten_attribute_list_from_additionals(
|
|
|
127
125
|
class PrintAnnotationSpecsAttribute(CommandLine):
|
|
128
126
|
COMMON_MESSAGE = "annofabcli annotation_specs list_attribute: error:"
|
|
129
127
|
|
|
130
|
-
def print_annotation_specs_attribute(
|
|
131
|
-
|
|
132
|
-
) -> None:
|
|
133
|
-
attribute_list = create_flatten_attribute_list_from_additionals(
|
|
134
|
-
annotation_specs_v3["additionals"], annotation_specs_v3["labels"], annotation_specs_v3["restrictions"]
|
|
135
|
-
)
|
|
128
|
+
def print_annotation_specs_attribute(self, annotation_specs_v3: dict[str, Any], output_format: FormatArgument, output: Optional[str] = None) -> None:
|
|
129
|
+
attribute_list = create_flatten_attribute_list_from_additionals(annotation_specs_v3["additionals"], annotation_specs_v3["labels"], annotation_specs_v3["restrictions"])
|
|
136
130
|
logger.info(f"{len(attribute_list)} 件の属性情報を出力します。")
|
|
137
131
|
if output_format == FormatArgument.CSV:
|
|
138
132
|
columns = [
|
|
@@ -161,9 +155,7 @@ class PrintAnnotationSpecsAttribute(CommandLine):
|
|
|
161
155
|
logger.warning(f"アノテーション仕様の履歴は{len(histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。")
|
|
162
156
|
return None
|
|
163
157
|
history = histories[-(before + 1)]
|
|
164
|
-
logger.info(
|
|
165
|
-
f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'"
|
|
166
|
-
)
|
|
158
|
+
logger.info(f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'")
|
|
167
159
|
return history["history_id"]
|
|
168
160
|
|
|
169
161
|
def main(self) -> None:
|
|
@@ -195,14 +187,11 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
195
187
|
argument_parser = ArgumentParser(parser)
|
|
196
188
|
|
|
197
189
|
required_group = parser.add_mutually_exclusive_group(required=True)
|
|
198
|
-
required_group.add_argument(
|
|
199
|
-
"-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。"
|
|
200
|
-
)
|
|
190
|
+
required_group.add_argument("-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。")
|
|
201
191
|
required_group.add_argument(
|
|
202
192
|
"--annotation_specs_json",
|
|
203
193
|
type=Path,
|
|
204
|
-
help="指定したアノテーション仕様のJSONファイルを指定します。"
|
|
205
|
-
"JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
194
|
+
help="指定したアノテーション仕様のJSONファイルを指定します。JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
206
195
|
)
|
|
207
196
|
|
|
208
197
|
# 過去のアノテーション仕様を参照するためのオプション
|
|
@@ -133,9 +133,7 @@ class PrintAnnotationSpecsAttribute(CommandLine):
|
|
|
133
133
|
logger.warning(f"アノテーション仕様の履歴は{len(histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。")
|
|
134
134
|
return None
|
|
135
135
|
history = histories[-(before + 1)]
|
|
136
|
-
logger.info(
|
|
137
|
-
f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'"
|
|
138
|
-
)
|
|
136
|
+
logger.info(f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'")
|
|
139
137
|
return history["history_id"]
|
|
140
138
|
|
|
141
139
|
def main(self) -> None:
|
|
@@ -169,14 +167,11 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
169
167
|
argument_parser = ArgumentParser(parser)
|
|
170
168
|
|
|
171
169
|
required_group = parser.add_mutually_exclusive_group(required=True)
|
|
172
|
-
required_group.add_argument(
|
|
173
|
-
"-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。"
|
|
174
|
-
)
|
|
170
|
+
required_group.add_argument("-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。")
|
|
175
171
|
required_group.add_argument(
|
|
176
172
|
"--annotation_specs_json",
|
|
177
173
|
type=Path,
|
|
178
|
-
help="指定したアノテーション仕様のJSONファイルを指定します。"
|
|
179
|
-
"JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
174
|
+
help="指定したアノテーション仕様のJSONファイルを指定します。JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
180
175
|
)
|
|
181
176
|
|
|
182
177
|
# 過去のアノテーション仕様を参照するためのオプション
|
|
@@ -50,7 +50,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
50
50
|
|
|
51
51
|
argument_parser.add_format(choices=[FormatArgument.CSV, FormatArgument.JSON, FormatArgument.PRETTY_JSON], default=FormatArgument.CSV)
|
|
52
52
|
argument_parser.add_output()
|
|
53
|
-
argument_parser.add_csv_format()
|
|
54
53
|
|
|
55
54
|
parser.set_defaults(subcommand_func=main)
|
|
56
55
|
|
|
@@ -119,9 +119,7 @@ class PrintAnnotationSpecsLabel(CommandLine):
|
|
|
119
119
|
logger.warning(f"アノテーション仕様の履歴は{len(histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。")
|
|
120
120
|
return None
|
|
121
121
|
history = histories[-(before + 1)]
|
|
122
|
-
logger.info(
|
|
123
|
-
f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'"
|
|
124
|
-
)
|
|
122
|
+
logger.info(f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'")
|
|
125
123
|
return history["history_id"]
|
|
126
124
|
|
|
127
125
|
def main(self) -> None:
|
|
@@ -156,14 +154,11 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
156
154
|
argument_parser = ArgumentParser(parser)
|
|
157
155
|
|
|
158
156
|
required_group = parser.add_mutually_exclusive_group(required=True)
|
|
159
|
-
required_group.add_argument(
|
|
160
|
-
"-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。"
|
|
161
|
-
)
|
|
157
|
+
required_group.add_argument("-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。")
|
|
162
158
|
required_group.add_argument(
|
|
163
159
|
"--annotation_specs_json",
|
|
164
160
|
type=Path,
|
|
165
|
-
help="指定したアノテーション仕様のJSONファイルを指定します。"
|
|
166
|
-
"JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
161
|
+
help="指定したアノテーション仕様のJSONファイルを指定します。JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
167
162
|
)
|
|
168
163
|
|
|
169
164
|
# 過去のアノテーション仕様を参照するためのオプション
|
|
@@ -42,7 +42,7 @@ class LabelAndAttribute(DataClassJsonMixin):
|
|
|
42
42
|
Notes:
|
|
43
43
|
APIレスポンスの ``additional_data_definition_id`` に相当します。
|
|
44
44
|
``additional_data_definition_id`` という名前がアノテーションJSONの `attributes` と対応していることが分かりにくかったので、`attribute_id`という名前に変えました。
|
|
45
|
-
"""
|
|
45
|
+
"""
|
|
46
46
|
attribute_name_en: Optional[str]
|
|
47
47
|
attribute_name_ja: Optional[str]
|
|
48
48
|
attribute_name_vi: Optional[str]
|
|
@@ -121,9 +121,7 @@ class PrintAnnotationSpecsLabelAndAttribute(CommandLine):
|
|
|
121
121
|
logger.warning(f"アノテーション仕様の履歴は{len(histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。")
|
|
122
122
|
return None
|
|
123
123
|
history = histories[-(before + 1)]
|
|
124
|
-
logger.info(
|
|
125
|
-
f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'"
|
|
126
|
-
)
|
|
124
|
+
logger.info(f"{history['updated_datetime']}のアノテーション仕様を出力します。 :: history_id='{history['history_id']}', comment='{history['comment']}'")
|
|
127
125
|
return history["history_id"]
|
|
128
126
|
|
|
129
127
|
def main(self) -> None:
|
|
@@ -158,14 +156,11 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
158
156
|
argument_parser = ArgumentParser(parser)
|
|
159
157
|
|
|
160
158
|
required_group = parser.add_mutually_exclusive_group(required=True)
|
|
161
|
-
required_group.add_argument(
|
|
162
|
-
"-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。"
|
|
163
|
-
)
|
|
159
|
+
required_group.add_argument("-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。")
|
|
164
160
|
required_group.add_argument(
|
|
165
161
|
"--annotation_specs_json",
|
|
166
162
|
type=Path,
|
|
167
|
-
help="指定したアノテーション仕様のJSONファイルを指定します。"
|
|
168
|
-
"JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
163
|
+
help="指定したアノテーション仕様のJSONファイルを指定します。JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
169
164
|
)
|
|
170
165
|
|
|
171
166
|
# 過去のアノテーション仕様を参照するためのオプション
|
|
@@ -82,14 +82,11 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
82
82
|
argument_parser = ArgumentParser(parser)
|
|
83
83
|
|
|
84
84
|
required_group = parser.add_mutually_exclusive_group(required=True)
|
|
85
|
-
required_group.add_argument(
|
|
86
|
-
"-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。"
|
|
87
|
-
)
|
|
85
|
+
required_group.add_argument("-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。")
|
|
88
86
|
required_group.add_argument(
|
|
89
87
|
"--annotation_specs_json",
|
|
90
88
|
type=Path,
|
|
91
|
-
help="指定したアノテーション仕様のJSONファイルを指定します。"
|
|
92
|
-
"JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
89
|
+
help="指定したアノテーション仕様のJSONファイルを指定します。JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
93
90
|
)
|
|
94
91
|
|
|
95
92
|
# 過去のアノテーション仕様を参照するためのオプション
|
|
@@ -124,10 +121,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
124
121
|
type=str,
|
|
125
122
|
choices=[e.value for e in OutputFormat],
|
|
126
123
|
default=OutputFormat.TEXT.value,
|
|
127
|
-
help=f"出力フォーマット\n"
|
|
128
|
-
"\n"
|
|
129
|
-
f"* {OutputFormat.TEXT.value}: 英語名のみ出力する形式\n"
|
|
130
|
-
f"* {OutputFormat.DETAILED_TEXT.value}: 属性IDや属性種類などの詳細情報を出力する形式\n",
|
|
124
|
+
help=f"出力フォーマット\n\n* {OutputFormat.TEXT.value}: 英語名のみ出力する形式\n* {OutputFormat.DETAILED_TEXT.value}: 属性IDや属性種類などの詳細情報を出力する形式\n",
|
|
131
125
|
)
|
|
132
126
|
|
|
133
127
|
parser.set_defaults(subcommand_func=main)
|
|
@@ -119,12 +119,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
119
119
|
"--json",
|
|
120
120
|
type=str,
|
|
121
121
|
required=True,
|
|
122
|
-
help=(
|
|
123
|
-
"変更したいラベルの色をJSON形式で指定してください。"
|
|
124
|
-
"keyがラベル英語名, valueがRGB値の配列です。\n"
|
|
125
|
-
f"(ex) ``{JSON_SAMPLE}`` \n"
|
|
126
|
-
"``file://`` を先頭に付けるとjsonファイルを指定できます。"
|
|
127
|
-
),
|
|
122
|
+
help=(f"変更したいラベルの色をJSON形式で指定してください。keyがラベル英語名, valueがRGB値の配列です。\n(ex) ``{JSON_SAMPLE}`` \n``file://`` を先頭に付けるとjsonファイルを指定できます。"),
|
|
128
123
|
)
|
|
129
124
|
|
|
130
125
|
parser.add_argument(
|
|
@@ -98,9 +98,7 @@ class DeleteCommentMain(CommandLineWithConfirm):
|
|
|
98
98
|
) -> bool:
|
|
99
99
|
task_id = task["task_id"]
|
|
100
100
|
if task["status"] not in [TaskStatus.NOT_STARTED.value, TaskStatus.WORKING.value, TaskStatus.BREAK.value]:
|
|
101
|
-
logger.warning(
|
|
102
|
-
f"task_id='{task_id}' : タスクの状態が未着手,作業中,休憩中 以外の状態なので、コメントを削除できません。(task_status='{task['status']}')" # noqa: E501
|
|
103
|
-
)
|
|
101
|
+
logger.warning(f"task_id='{task_id}' : タスクの状態が未着手,作業中,休憩中 以外の状態なので、コメントを削除できません。(task_status='{task['status']}')")
|
|
104
102
|
return False
|
|
105
103
|
return True
|
|
106
104
|
|
|
@@ -151,13 +149,9 @@ class DeleteCommentMain(CommandLineWithConfirm):
|
|
|
151
149
|
if len(request_body) > 0:
|
|
152
150
|
self.service.api.batch_update_comments(self.project_id, task_id, input_data_id, request_body=request_body)
|
|
153
151
|
added_comments_count += 1
|
|
154
|
-
logger.debug(
|
|
155
|
-
f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: {len(request_body)}件のコメントを削除しました。"
|
|
156
|
-
)
|
|
152
|
+
logger.debug(f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: {len(request_body)}件のコメントを削除しました。")
|
|
157
153
|
else:
|
|
158
|
-
logger.warning(
|
|
159
|
-
f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: 削除できるコメントは存在しませんでした。"
|
|
160
|
-
)
|
|
154
|
+
logger.warning(f"{logging_prefix} :: task_id='{task_id}', input_data_id='{input_data_id}' :: 削除できるコメントは存在しませんでした。")
|
|
161
155
|
|
|
162
156
|
except Exception: # pylint: disable=broad-except
|
|
163
157
|
logger.warning(
|
|
@@ -18,6 +18,7 @@ from annofabapi.models import CommentType
|
|
|
18
18
|
|
|
19
19
|
import annofabcli
|
|
20
20
|
import annofabcli.common.cli
|
|
21
|
+
from annofabcli.comment.list_comment import create_empty_df_comment, create_reply_counter
|
|
21
22
|
from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login
|
|
22
23
|
from annofabcli.common.download import DownloadingFile
|
|
23
24
|
from annofabcli.common.enums import FormatArgument
|
|
@@ -62,12 +63,19 @@ class ListAllCommentMain:
|
|
|
62
63
|
if comment_type is not None:
|
|
63
64
|
comment_list = [e for e in comment_list if e["comment_type"] == comment_type.value]
|
|
64
65
|
|
|
66
|
+
# 返信回数を算出する
|
|
67
|
+
reply_counter = create_reply_counter(comment_list)
|
|
68
|
+
for c in comment_list:
|
|
69
|
+
key = (c["task_id"], c["input_data_id"], c["comment_id"])
|
|
70
|
+
c["reply_count"] = reply_counter.get(key, 0)
|
|
71
|
+
|
|
65
72
|
if exclude_reply:
|
|
66
73
|
# 返信コメントを除外する
|
|
67
74
|
comment_list = [e for e in comment_list if e["comment_node"]["_type"] != "Reply"]
|
|
68
75
|
|
|
69
76
|
visualize = AddProps(self.service, project_id)
|
|
70
77
|
comment_list = [visualize.add_properties_to_comment(e) for e in comment_list]
|
|
78
|
+
|
|
71
79
|
return comment_list
|
|
72
80
|
|
|
73
81
|
|
|
@@ -93,7 +101,11 @@ class ListAllComment(CommandLine):
|
|
|
93
101
|
|
|
94
102
|
output_format = FormatArgument(args.format)
|
|
95
103
|
if output_format == FormatArgument.CSV:
|
|
96
|
-
|
|
104
|
+
if len(comment_list) > 0:
|
|
105
|
+
df = pandas.json_normalize(comment_list)
|
|
106
|
+
else:
|
|
107
|
+
df = create_empty_df_comment()
|
|
108
|
+
|
|
97
109
|
print_csv(df, output=args.output)
|
|
98
110
|
else:
|
|
99
111
|
print_according_to_format(comment_list, output_format, output=args.output)
|
|
@@ -117,8 +129,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
117
129
|
parser.add_argument(
|
|
118
130
|
"--comment_json",
|
|
119
131
|
type=Path,
|
|
120
|
-
help="コメント情報が記載されたJSONファイルのパスを指定すると、JSONに記載された情報を元にコメント一覧を出力します。\
|
|
121
|
-
"JSONファイルは ``$ annofabcli comment download`` コマンドで取得できます。",
|
|
132
|
+
help="コメント情報が記載されたJSONファイルのパスを指定すると、JSONに記載された情報を元にコメント一覧を出力します。\nJSONファイルは ``$ annofabcli comment download`` コマンドで取得できます。",
|
|
122
133
|
)
|
|
123
134
|
|
|
124
135
|
parser.add_argument("--exclude_reply", action="store_true", help="返信コメントを除外します。")
|
|
@@ -133,7 +144,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
133
144
|
default=FormatArgument.CSV,
|
|
134
145
|
)
|
|
135
146
|
argument_parser.add_output()
|
|
136
|
-
argument_parser.add_csv_format()
|
|
137
147
|
|
|
138
148
|
parser.set_defaults(subcommand_func=main)
|
|
139
149
|
|
|
@@ -149,7 +159,7 @@ def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argpa
|
|
|
149
159
|
subcommand_help = "すべてのコメントの一覧を出力します。"
|
|
150
160
|
description = (
|
|
151
161
|
"すべてのコメントの一覧を出力します。\n"
|
|
152
|
-
"コメント一覧は、コマンドを実行した日の02:00(JST)頃の状態です。最新のコメント情報を取得したい場合は、 ``annofabcli comment list`` コマンドを実行してください。"
|
|
162
|
+
"コメント一覧は、コマンドを実行した日の02:00(JST)頃の状態です。最新のコメント情報を取得したい場合は、 ``annofabcli comment list`` コマンドを実行してください。"
|
|
153
163
|
)
|
|
154
164
|
|
|
155
165
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description=description)
|