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/__main__.py
CHANGED
|
@@ -74,7 +74,7 @@ def main(arguments: Optional[list[str]] = None) -> None:
|
|
|
74
74
|
warn_pandas_copy_on_write()
|
|
75
75
|
parser = create_parser()
|
|
76
76
|
|
|
77
|
-
if arguments is None:
|
|
77
|
+
if arguments is None:
|
|
78
78
|
args = parser.parse_args()
|
|
79
79
|
else:
|
|
80
80
|
args = parser.parse_args(arguments)
|
|
@@ -66,7 +66,7 @@ def _get_additional_data_v1(additional_data: dict[str, Any], attribute_value: At
|
|
|
66
66
|
)
|
|
67
67
|
if len(tmp) > 1:
|
|
68
68
|
raise ValueError(
|
|
69
|
-
f"アノテーション仕様の'{get_attribute_name(additional_data)}'属性に、選択肢名(英語)が'{attribute_value}'である選択肢が複数({len(tmp)} 個)存在します。"
|
|
69
|
+
f"アノテーション仕様の'{get_attribute_name(additional_data)}'属性に、選択肢名(英語)が'{attribute_value}'である選択肢が複数({len(tmp)} 個)存在します。"
|
|
70
70
|
f" :: additional_data_definition_id='{additional_data_definition_id}'"
|
|
71
71
|
)
|
|
72
72
|
|
|
@@ -95,13 +95,9 @@ def _get_additional_data_v2(additional_data: dict[str, Any], attribute_value: At
|
|
|
95
95
|
tmp = [e for e in additional_data["choices"] if get_english_message(e["name"]) == choice_name_en]
|
|
96
96
|
|
|
97
97
|
if len(tmp) == 0: # pylint: disable=no-else-raise
|
|
98
|
-
raise ValueError(
|
|
99
|
-
f"アノテーション仕様の'{get_attribute_name(additional_data)}'属性に、選択肢名(英語)が'{choice_name_en}'である選択肢は存在しません。"
|
|
100
|
-
)
|
|
98
|
+
raise ValueError(f"アノテーション仕様の'{get_attribute_name(additional_data)}'属性に、選択肢名(英語)が'{choice_name_en}'である選択肢は存在しません。")
|
|
101
99
|
elif len(tmp) > 1:
|
|
102
|
-
raise ValueError(
|
|
103
|
-
f"アノテーション仕様の'{get_attribute_name(additional_data)}'属性に、選択肢名(英語)が'{choice_name_en}'である選択肢が複数({len(tmp)} 個)存在します。" # noqa: E501
|
|
104
|
-
)
|
|
100
|
+
raise ValueError(f"アノテーション仕様の'{get_attribute_name(additional_data)}'属性に、選択肢名(英語)が'{choice_name_en}'である選択肢が複数({len(tmp)} 個)存在します。")
|
|
105
101
|
|
|
106
102
|
return tmp[0]["choice_id"]
|
|
107
103
|
|
|
@@ -137,9 +133,7 @@ def _get_additional_data_v2(additional_data: dict[str, Any], attribute_value: At
|
|
|
137
133
|
return {"definition_id": additional_data_definition_id, "value": result_value}
|
|
138
134
|
|
|
139
135
|
|
|
140
|
-
def convert_attributes_from_cli_to_api(
|
|
141
|
-
attributes: dict[str, AttributeValue], annotation_specs: dict[str, Any], *, label_id: Optional[str] = None
|
|
142
|
-
) -> list[AdditionalDataV1]:
|
|
136
|
+
def convert_attributes_from_cli_to_api(attributes: dict[str, AttributeValue], annotation_specs: dict[str, Any], *, label_id: Optional[str] = None) -> list[AdditionalDataV1]:
|
|
143
137
|
"""
|
|
144
138
|
CLI用の属性をAPI用の属性に変換します。
|
|
145
139
|
|
|
@@ -179,20 +173,14 @@ def convert_attributes_from_cli_to_api(
|
|
|
179
173
|
if label_info is None:
|
|
180
174
|
error_message = f"アノテーション仕様に、属性名(英語)が'{attribute_name}'である属性は存在しません。"
|
|
181
175
|
else:
|
|
182
|
-
error_message = (
|
|
183
|
-
f"アノテーション仕様の'{get_label_name(label_info)}'ラベルに、"
|
|
184
|
-
f"属性名(英語)が'{attribute_name}'である属性は存在しません。 :: label_id='{label_id}'"
|
|
185
|
-
)
|
|
176
|
+
error_message = f"アノテーション仕様の'{get_label_name(label_info)}'ラベルに、属性名(英語)が'{attribute_name}'である属性は存在しません。 :: label_id='{label_id}'"
|
|
186
177
|
raise ValueError(error_message)
|
|
187
178
|
|
|
188
179
|
if len(tmp) > 1:
|
|
189
180
|
if label_info is None:
|
|
190
181
|
error_message = f"アノテーション仕様に、属性名(英語)が'{attribute_name}'である属性が複数存在します。"
|
|
191
182
|
else:
|
|
192
|
-
error_message = (
|
|
193
|
-
f"アノテーション仕様の'{get_label_name(label_info)}'ラベルに、"
|
|
194
|
-
f"属性名(英語)が'{attribute_name}'である属性が複数存在します。 :: label_id='{label_id}'"
|
|
195
|
-
)
|
|
183
|
+
error_message = f"アノテーション仕様の'{get_label_name(label_info)}'ラベルに、属性名(英語)が'{attribute_name}'である属性が複数存在します。 :: label_id='{label_id}'"
|
|
196
184
|
raise ValueError(error_message)
|
|
197
185
|
additional_data = tmp[0]
|
|
198
186
|
attributes_for_webapi.append(_get_additional_data_v1(additional_data, attribute_value))
|
|
@@ -200,9 +188,7 @@ def convert_attributes_from_cli_to_api(
|
|
|
200
188
|
return attributes_for_webapi
|
|
201
189
|
|
|
202
190
|
|
|
203
|
-
def convert_attributes_from_cli_to_additional_data_list_v2(
|
|
204
|
-
attributes: dict[str, AttributeValue], annotation_specs: dict[str, Any], *, label_id: Optional[str] = None
|
|
205
|
-
) -> list[dict[str, Any]]:
|
|
191
|
+
def convert_attributes_from_cli_to_additional_data_list_v2(attributes: dict[str, AttributeValue], annotation_specs: dict[str, Any], *, label_id: Optional[str] = None) -> list[dict[str, Any]]:
|
|
206
192
|
"""
|
|
207
193
|
CLI用の属性情報をAPI用の `AdditionalDataV2` に相当するdictに変換します。
|
|
208
194
|
|
|
@@ -242,20 +228,14 @@ def convert_attributes_from_cli_to_additional_data_list_v2(
|
|
|
242
228
|
if label_info is None:
|
|
243
229
|
error_message = f"アノテーション仕様に、属性名(英語)が'{attribute_name}'である属性は存在しません。"
|
|
244
230
|
else:
|
|
245
|
-
error_message = (
|
|
246
|
-
f"アノテーション仕様の'{get_label_name(label_info)}'ラベルに、"
|
|
247
|
-
f"属性名(英語)が'{attribute_name}'である属性は存在しません。 :: label_id='{label_id}'"
|
|
248
|
-
)
|
|
231
|
+
error_message = f"アノテーション仕様の'{get_label_name(label_info)}'ラベルに、属性名(英語)が'{attribute_name}'である属性は存在しません。 :: label_id='{label_id}'"
|
|
249
232
|
raise ValueError(error_message)
|
|
250
233
|
|
|
251
234
|
elif len(tmp) > 1:
|
|
252
235
|
if label_info is None:
|
|
253
236
|
error_message = f"アノテーション仕様に、属性名(英語)が'{attribute_name}'である属性が複数存在します。"
|
|
254
237
|
else:
|
|
255
|
-
error_message = (
|
|
256
|
-
f"アノテーション仕様の'{get_label_name(label_info)}'ラベルに、"
|
|
257
|
-
f"属性名(英語)が'{attribute_name}'である属性が複数存在します。 :: label_id='{label_id}'"
|
|
258
|
-
)
|
|
238
|
+
error_message = f"アノテーション仕様の'{get_label_name(label_info)}'ラベルに、属性名(英語)が'{attribute_name}'である属性が複数存在します。 :: label_id='{label_id}'"
|
|
259
239
|
raise ValueError(error_message)
|
|
260
240
|
additional_data = tmp[0]
|
|
261
241
|
result.append(_get_additional_data_v2(additional_data, attribute_value))
|
|
@@ -58,9 +58,7 @@ class ChangeAnnotationAttributesMain(CommandLineWithConfirm):
|
|
|
58
58
|
|
|
59
59
|
self.dump_annotation_obj = DumpAnnotationMain(service, project_id)
|
|
60
60
|
|
|
61
|
-
def change_annotation_attributes(
|
|
62
|
-
self, annotation_list: list[dict[str, Any]], additional_data_list: list[dict[str, Any]]
|
|
63
|
-
) -> Optional[list[dict[str, Any]]]:
|
|
61
|
+
def change_annotation_attributes(self, annotation_list: list[dict[str, Any]], additional_data_list: list[dict[str, Any]]) -> Optional[list[dict[str, Any]]]:
|
|
64
62
|
"""
|
|
65
63
|
アノテーション属性値を変更する。
|
|
66
64
|
|
|
@@ -270,9 +268,7 @@ class ChangeAttributesOfAnnotation(CommandLine):
|
|
|
270
268
|
return annotation_query_for_cli.to_query_for_api(annotation_specs)
|
|
271
269
|
|
|
272
270
|
@classmethod
|
|
273
|
-
def get_additional_data_list_from_cli_attributes(
|
|
274
|
-
cls, str_attributes: str, annotation_specs: dict[str, Any], label_id: Optional[str]
|
|
275
|
-
) -> list[dict[str, Any]]:
|
|
271
|
+
def get_additional_data_list_from_cli_attributes(cls, str_attributes: str, annotation_specs: dict[str, Any], label_id: Optional[str]) -> list[dict[str, Any]]:
|
|
276
272
|
"""
|
|
277
273
|
CLIから受け取った`--attributes`の値から、APIに渡す属性情報(`AdditionalDataListV2`)を返します。
|
|
278
274
|
"""
|
|
@@ -297,9 +293,7 @@ class ChangeAttributesOfAnnotation(CommandLine):
|
|
|
297
293
|
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|
|
298
294
|
|
|
299
295
|
try:
|
|
300
|
-
additional_data_list = self.get_additional_data_list_from_cli_attributes(
|
|
301
|
-
args.attributes, annotation_specs, label_id=annotation_query.label_id
|
|
302
|
-
)
|
|
296
|
+
additional_data_list = self.get_additional_data_list_from_cli_attributes(args.attributes, annotation_specs, label_id=annotation_query.label_id)
|
|
303
297
|
except ValueError as e:
|
|
304
298
|
print(f"{self.COMMON_MESSAGE} argument '--attributes' の値が不正です。 :: {e}", file=sys.stderr) # noqa: T201
|
|
305
299
|
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|
|
@@ -319,7 +313,7 @@ class ChangeAttributesOfAnnotation(CommandLine):
|
|
|
319
313
|
if args.force: # noqa: SIM102
|
|
320
314
|
if not self.facade.contains_any_project_member_role(project_id, [ProjectMemberRole.OWNER]):
|
|
321
315
|
print( # noqa: T201
|
|
322
|
-
f"{self.COMMON_MESSAGE} argument --force : '--force' 引数を利用するにはプロジェクトのオーナーロールを持つユーザーで実行する必要があります。",
|
|
316
|
+
f"{self.COMMON_MESSAGE} argument --force : '--force' 引数を利用するにはプロジェクトのオーナーロールを持つユーザーで実行する必要があります。",
|
|
323
317
|
file=sys.stderr,
|
|
324
318
|
)
|
|
325
319
|
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|
|
@@ -352,9 +346,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
352
346
|
"--annotation_query",
|
|
353
347
|
type=str,
|
|
354
348
|
required=True,
|
|
355
|
-
help="変更対象のアノテーションを検索する条件をJSON
|
|
356
|
-
"``file://`` を先頭に付けると、JSON形式のファイルを指定できます。"
|
|
357
|
-
f"(ex): ``{json.dumps(EXAMPLE_ANNOTATION_QUERY)}``",
|
|
349
|
+
help=f"変更対象のアノテーションを検索する条件をJSON形式で指定します。``file://`` を先頭に付けると、JSON形式のファイルを指定できます。(ex): ``{json.dumps(EXAMPLE_ANNOTATION_QUERY)}``",
|
|
358
350
|
)
|
|
359
351
|
|
|
360
352
|
EXAMPLE_ATTRIBUTES = '{"occluded": false}' # noqa: N806
|
|
@@ -375,7 +367,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
375
367
|
"--backup",
|
|
376
368
|
type=str,
|
|
377
369
|
required=False,
|
|
378
|
-
help="アノテーションのバックアップを保存するディレクトリを指定してください。アノテーションの復元は ``annotation restore`` コマンドで実現できます。",
|
|
370
|
+
help="アノテーションのバックアップを保存するディレクトリを指定してください。アノテーションの復元は ``annotation restore`` コマンドで実現できます。",
|
|
379
371
|
)
|
|
380
372
|
parser.add_argument(
|
|
381
373
|
"--parallelism",
|
|
@@ -156,15 +156,10 @@ class ChangePropertiesOfAnnotationMain(CommandLineWithConfirm):
|
|
|
156
156
|
logger.warning(f"task_id = '{task_id}' は存在しません。")
|
|
157
157
|
return False
|
|
158
158
|
|
|
159
|
-
logger.debug(
|
|
160
|
-
f"{logger_prefix}task_id='{task_id}', phase={dict_task['phase']}, status={dict_task['status']}, "
|
|
161
|
-
f"updated_datetime={dict_task['updated_datetime']}"
|
|
162
|
-
)
|
|
159
|
+
logger.debug(f"{logger_prefix}task_id='{task_id}', phase={dict_task['phase']}, status={dict_task['status']}, updated_datetime={dict_task['updated_datetime']}")
|
|
163
160
|
|
|
164
161
|
if dict_task["status"] in [TaskStatus.WORKING.value, TaskStatus.COMPLETE.value]:
|
|
165
|
-
logger.info(
|
|
166
|
-
f"タスク'{task_id}'は作業中または受入完了状態のため、アノテーションプロパティの変更をスキップします。 status={dict_task['status']}"
|
|
167
|
-
)
|
|
162
|
+
logger.info(f"タスク'{task_id}'は作業中または受入完了状態のため、アノテーションプロパティの変更をスキップします。 status={dict_task['status']}")
|
|
168
163
|
return False
|
|
169
164
|
|
|
170
165
|
old_account_id: Optional[str] = dict_task["account_id"]
|
|
@@ -375,9 +370,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
375
370
|
"--properties",
|
|
376
371
|
type=str,
|
|
377
372
|
required=True,
|
|
378
|
-
help="変更後のプロパティをJSON形式で指定します。変更可能なキーは ``is_protected``
|
|
379
|
-
"``file://`` を先頭に付けると、JSON形式のファイルを指定できます。"
|
|
380
|
-
f"(ex): ``{EXAMPLE_PROPERTIES}``",
|
|
373
|
+
help=f"変更後のプロパティをJSON形式で指定します。変更可能なキーは ``is_protected`` です。``file://`` を先頭に付けると、JSON形式のファイルを指定できます。(ex): ``{EXAMPLE_PROPERTIES}``",
|
|
381
374
|
)
|
|
382
375
|
|
|
383
376
|
parser.add_argument(
|
|
@@ -390,7 +383,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
390
383
|
"--backup",
|
|
391
384
|
type=str,
|
|
392
385
|
required=False,
|
|
393
|
-
help="アノテーションのバックアップを保存するディレクトリを指定してください。アノテーションの復元は ``annotation restore`` コマンドで実現できます。",
|
|
386
|
+
help="アノテーションのバックアップを保存するディレクトリを指定してください。アノテーションの復元は ``annotation restore`` コマンドで実現できます。",
|
|
394
387
|
)
|
|
395
388
|
|
|
396
389
|
parser.add_argument(
|
|
@@ -408,7 +401,7 @@ def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argpa
|
|
|
408
401
|
subcommand_help = "アノテーションのプロパティを変更します。"
|
|
409
402
|
description = (
|
|
410
403
|
"アノテーションのプロパティを一括で変更します。ただし、作業中状態のタスクのアノテーションのプロパティは変更できません。"
|
|
411
|
-
"間違えてアノテーションのプロパティを変更したときに復元できるようにするため、 ``--backup`` でバックアップ用のディレクトリを指定することを推奨します。"
|
|
404
|
+
"間違えてアノテーションのプロパティを変更したときに復元できるようにするため、 ``--backup`` でバックアップ用のディレクトリを指定することを推奨します。"
|
|
412
405
|
)
|
|
413
406
|
epilog = "オーナロールを持つユーザで実行してください。"
|
|
414
407
|
|
|
@@ -158,8 +158,7 @@ class CopyAnnotationMain(CommandLineWithConfirm):
|
|
|
158
158
|
if len(src_input_data_id_list) != len(dest_input_data_id_list):
|
|
159
159
|
max_frame_number = min(len(src_input_data_id_list), len(dest_input_data_id_list))
|
|
160
160
|
logger.debug(
|
|
161
|
-
f"コピー元タスク'{copy_target.src_task_id}'の1〜{max_frame_number}
|
|
162
|
-
f"コピー先タスク'{copy_target.dest_task_id}'の1〜{max_frame_number}フレームにコピーします。"
|
|
161
|
+
f"コピー元タスク'{copy_target.src_task_id}'の1〜{max_frame_number}フレームのアノテーションを、コピー先タスク'{copy_target.dest_task_id}'の1〜{max_frame_number}フレームにコピーします。"
|
|
163
162
|
)
|
|
164
163
|
|
|
165
164
|
copy_count = 0
|
|
@@ -207,9 +206,7 @@ class CopyAnnotationMain(CommandLineWithConfirm):
|
|
|
207
206
|
アノテーションをコピーしたかどうか。
|
|
208
207
|
|
|
209
208
|
"""
|
|
210
|
-
src_annotation = self.service.wrapper.get_editor_annotation_or_none(
|
|
211
|
-
project_id=self.project_id, task_id=copy_target.src_task_id, input_data_id=copy_target.src_input_data_id
|
|
212
|
-
)
|
|
209
|
+
src_annotation = self.service.wrapper.get_editor_annotation_or_none(project_id=self.project_id, task_id=copy_target.src_task_id, input_data_id=copy_target.src_input_data_id)
|
|
213
210
|
if src_annotation is None:
|
|
214
211
|
logger.warning(
|
|
215
212
|
f"task_id='{copy_target.src_task_id}'のタスクが存在しないか、またはtask_id='{copy_target.src_task_id}'のタスクにinput_data_id='{copy_target.src_input_data_id}'の入力データが存在しません。"
|
|
@@ -218,9 +215,7 @@ class CopyAnnotationMain(CommandLineWithConfirm):
|
|
|
218
215
|
|
|
219
216
|
src_anno_details = src_annotation["details"]
|
|
220
217
|
|
|
221
|
-
dest_annotation = self.service.wrapper.get_editor_annotation_or_none(
|
|
222
|
-
project_id=self.project_id, task_id=copy_target.dest_task_id, input_data_id=copy_target.dest_input_data_id
|
|
223
|
-
)
|
|
218
|
+
dest_annotation = self.service.wrapper.get_editor_annotation_or_none(project_id=self.project_id, task_id=copy_target.dest_task_id, input_data_id=copy_target.dest_input_data_id)
|
|
224
219
|
if dest_annotation is None:
|
|
225
220
|
logger.warning(
|
|
226
221
|
f"task_id='{copy_target.dest_task_id}'のタスクが存在しないか、またはtask_id='{copy_target.dest_task_id}'のタスクにinput_data_id='{copy_target.dest_input_data_id}'の入力データが存在しません。"
|
|
@@ -394,8 +389,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
394
389
|
overwrite_merge_group.add_argument(
|
|
395
390
|
"--overwrite",
|
|
396
391
|
action="store_true",
|
|
397
|
-
help="コピー先にアノテーションが存在する場合、 ``--overwrite``
|
|
398
|
-
"指定しなければ、アノテーションのコピーをスキップします。",
|
|
392
|
+
help="コピー先にアノテーションが存在する場合、 ``--overwrite`` を指定していれば、すでに存在するアノテーションを削除してコピーします。指定しなければ、アノテーションのコピーをスキップします。",
|
|
399
393
|
)
|
|
400
394
|
overwrite_merge_group.add_argument(
|
|
401
395
|
"--merge",
|
|
@@ -135,10 +135,7 @@ class DeleteAnnotationMain(CommandLineWithConfirm):
|
|
|
135
135
|
|
|
136
136
|
if not self.is_force: # noqa: SIM102
|
|
137
137
|
if task.status == TaskStatus.COMPLETE:
|
|
138
|
-
logger.info(
|
|
139
|
-
f"task_id='{task_id}' :: タスクが完了状態のため、スキップします。"
|
|
140
|
-
f"完了状態のタスクのアノテーションを削除するには、`--force`オプションを指定してください。"
|
|
141
|
-
)
|
|
138
|
+
logger.info(f"task_id='{task_id}' :: タスクが完了状態のため、スキップします。完了状態のタスクのアノテーションを削除するには、`--force`オプションを指定してください。")
|
|
142
139
|
return
|
|
143
140
|
|
|
144
141
|
annotation_list = self.get_annotation_list_for_task(task_id, annotation_query=annotation_query)
|
|
@@ -197,10 +194,7 @@ class DeleteAnnotationMain(CommandLineWithConfirm):
|
|
|
197
194
|
task_id = editor_annotation["task_id"]
|
|
198
195
|
input_data_id = editor_annotation["input_data_id"]
|
|
199
196
|
if len(editor_annotation["details"]) == 0:
|
|
200
|
-
logger.warning(
|
|
201
|
-
f"task_id='{task_id}', input_data_id='{input_data_id}' にはアノテーションが存在しません。以下のアノテーションの削除をスキップします。 :: " # noqa: E501
|
|
202
|
-
f"annotation_ids={annotation_ids}"
|
|
203
|
-
)
|
|
197
|
+
logger.warning(f"task_id='{task_id}', input_data_id='{input_data_id}' にはアノテーションが存在しません。以下のアノテーションの削除をスキップします。 :: annotation_ids={annotation_ids}")
|
|
204
198
|
return 0, len(annotation_ids)
|
|
205
199
|
|
|
206
200
|
# annotation_idでフィルタ
|
|
@@ -209,9 +203,7 @@ class DeleteAnnotationMain(CommandLineWithConfirm):
|
|
|
209
203
|
nonexistent_annotation_ids = annotation_ids - existent_annotation_ids
|
|
210
204
|
|
|
211
205
|
if len(nonexistent_annotation_ids) > 0:
|
|
212
|
-
logger.warning(
|
|
213
|
-
f"次のアノテーションは存在しないので、削除できません。 :: task_id='{task_id}', input_data_id='{input_data_id}', annotation_id='{nonexistent_annotation_ids}'" # noqa: E501
|
|
214
|
-
)
|
|
206
|
+
logger.warning(f"次のアノテーションは存在しないので、削除できません。 :: task_id='{task_id}', input_data_id='{input_data_id}', annotation_id='{nonexistent_annotation_ids}'")
|
|
215
207
|
|
|
216
208
|
if len(filtered_details) == 0:
|
|
217
209
|
logger.info(f"task_id='{task_id}', input_data_id='{input_data_id}' には削除対象のアノテーションが存在しないので、スキップします。")
|
|
@@ -241,9 +233,7 @@ class DeleteAnnotationMain(CommandLineWithConfirm):
|
|
|
241
233
|
logger.warning(f"task_id='{task_id}', input_data_id='{input_data_id}' :: アノテーションの削除に失敗しました。", exc_info=True)
|
|
242
234
|
# `batchUpdateAnnotations` APIでエラーになった場合、途中までは削除されるので、`len(annotation_ids)` 件削除に失敗したとは限らない。
|
|
243
235
|
# そのため、再度アノテーション情報を取得して、削除できたアノテーション数と削除できなかったアノテーション数を取得する。
|
|
244
|
-
new_editor_annotation, _ = self.service.api.get_editor_annotation(
|
|
245
|
-
self.project_id, task_id=task_id, input_data_id=input_data_id, query_params={"v": "2"}
|
|
246
|
-
)
|
|
236
|
+
new_editor_annotation, _ = self.service.api.get_editor_annotation(self.project_id, task_id=task_id, input_data_id=input_data_id, query_params={"v": "2"})
|
|
247
237
|
new_annotation_ids = {e["annotation_id"] for e in new_editor_annotation["details"]}
|
|
248
238
|
deleted_annotation_count = len(existent_annotation_ids - new_annotation_ids)
|
|
249
239
|
failed_to_delete_annotation_count = len(existent_annotation_ids) - deleted_annotation_count
|
|
@@ -307,13 +297,10 @@ class DeleteAnnotationMain(CommandLineWithConfirm):
|
|
|
307
297
|
for input_data_id, annotation_ids in sub_grouped.items():
|
|
308
298
|
# 指定input_data_idの全annotationを取得
|
|
309
299
|
# TODO どこかのタイミングで、"v=2"のアノテーションを取得するようにする
|
|
310
|
-
editor_annotation = self.service.wrapper.get_editor_annotation_or_none(
|
|
311
|
-
self.project_id, task_id=task_id, input_data_id=input_data_id, query_params={"v": "1"}
|
|
312
|
-
)
|
|
300
|
+
editor_annotation = self.service.wrapper.get_editor_annotation_or_none(self.project_id, task_id=task_id, input_data_id=input_data_id, query_params={"v": "1"})
|
|
313
301
|
if editor_annotation is None:
|
|
314
302
|
logger.warning(
|
|
315
|
-
f"task_id='{task_id}'のタスクに、input_data_id='{input_data_id}'の入力データが含まれていません。 アノテーションの削除をスキップします。 :: "
|
|
316
|
-
f"annotation_ids={annotation_ids}"
|
|
303
|
+
f"task_id='{task_id}'のタスクに、input_data_id='{input_data_id}'の入力データが含まれていません。 アノテーションの削除をスキップします。 :: annotation_ids={annotation_ids}"
|
|
317
304
|
)
|
|
318
305
|
failed_to_delete_annotation_count += len(annotation_ids)
|
|
319
306
|
continue
|
|
@@ -322,9 +309,7 @@ class DeleteAnnotationMain(CommandLineWithConfirm):
|
|
|
322
309
|
(backup_dir / task_id).mkdir(exist_ok=True, parents=True)
|
|
323
310
|
self.dump_annotation_obj.dump_editor_annotation(editor_annotation, json_path=backup_dir / task_id / f"{input_data_id}.json")
|
|
324
311
|
|
|
325
|
-
sub_deleted_annotation_count, sub_failed_to_delete_annotation_count = self.delete_annotation_by_annotation_ids(
|
|
326
|
-
editor_annotation, set(annotation_ids)
|
|
327
|
-
)
|
|
312
|
+
sub_deleted_annotation_count, sub_failed_to_delete_annotation_count = self.delete_annotation_by_annotation_ids(editor_annotation, set(annotation_ids))
|
|
328
313
|
deleted_annotation_count += sub_deleted_annotation_count
|
|
329
314
|
failed_to_delete_annotation_count += sub_failed_to_delete_annotation_count
|
|
330
315
|
|
|
@@ -461,14 +446,13 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
461
446
|
parser.add_argument(
|
|
462
447
|
"--force",
|
|
463
448
|
action="store_true",
|
|
464
|
-
help="
|
|
465
|
-
"ただし、完了状態のタスクを削除するには、オーナーロールを持つユーザーが実行する必要があります。",
|
|
449
|
+
help="指定した場合は、完了状態のタスクのアノテーションも削除します。ただし、完了状態のタスクを削除するには、オーナーロールを持つユーザーが実行する必要があります。",
|
|
466
450
|
)
|
|
467
451
|
parser.add_argument(
|
|
468
452
|
"--backup",
|
|
469
453
|
type=str,
|
|
470
454
|
required=False,
|
|
471
|
-
help="アノテーションのバックアップを保存するディレクトリを指定してください。アノテーションの復元は ``annotation restore`` コマンドで実現できます。",
|
|
455
|
+
help="アノテーションのバックアップを保存するディレクトリを指定してください。アノテーションの復元は ``annotation restore`` コマンドで実現できます。",
|
|
472
456
|
)
|
|
473
457
|
parser.set_defaults(subcommand_func=main)
|
|
474
458
|
|
|
@@ -480,7 +464,7 @@ def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argpa
|
|
|
480
464
|
"タスク配下のアノテーションを削除します。ただし、作業中状態のタスクのアノテーションは削除できません。"
|
|
481
465
|
"間違えてアノテーションを削除したときに復元できるようにするため、 ``--backup`` でバックアップ用のディレクトリを指定することを推奨します。"
|
|
482
466
|
)
|
|
483
|
-
epilog = "オーナーまたはチェッカーロールを持つユーザで実行してください。ただし``--force``オプションを指定した場合は、オーナーロールを持つユーザで実行してください。"
|
|
467
|
+
epilog = "オーナーまたはチェッカーロールを持つユーザで実行してください。ただし``--force``オプションを指定した場合は、オーナーロールを持つユーザで実行してください。"
|
|
484
468
|
|
|
485
469
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description, epilog=epilog)
|
|
486
470
|
parse_args(parser)
|
|
@@ -161,10 +161,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
161
161
|
def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
|
|
162
162
|
subcommand_name = "dump"
|
|
163
163
|
subcommand_help = "``annotation restore`` コマンドに読み込ませることができるアノテーション情報を出力します。"
|
|
164
|
-
description =
|
|
165
|
-
"``annotation restore`` コマンドに読み込ませることができるアノテーション情報を出力します。"
|
|
166
|
-
"アノテーションのバックアップ目的で利用することを想定しています。"
|
|
167
|
-
)
|
|
164
|
+
description = "``annotation restore`` コマンドに読み込ませることができるアノテーション情報を出力します。アノテーションのバックアップ目的で利用することを想定しています。"
|
|
168
165
|
|
|
169
166
|
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
|
|
170
167
|
parse_args(parser)
|
|
@@ -200,9 +200,7 @@ class AnnotationConverter:
|
|
|
200
200
|
try:
|
|
201
201
|
choice = get_choice(choices, choice_name=str(attribute_value))
|
|
202
202
|
except ValueError:
|
|
203
|
-
logger.warning(
|
|
204
|
-
f"アノテーション仕様の属性'{attribute_name}'に選択肢名(英語)が'{attribute_value}'である選択肢情報は存在しないか、複数存在します。 :: {log_message_suffix}" # noqa: E501
|
|
205
|
-
)
|
|
203
|
+
logger.warning(f"アノテーション仕様の属性'{attribute_name}'に選択肢名(英語)が'{attribute_value}'である選択肢情報は存在しないか、複数存在します。 :: {log_message_suffix}")
|
|
206
204
|
if self.is_strict:
|
|
207
205
|
raise
|
|
208
206
|
return None
|
|
@@ -214,9 +212,7 @@ class AnnotationConverter:
|
|
|
214
212
|
try:
|
|
215
213
|
choice = get_choice(choices, choice_name=str(attribute_value))
|
|
216
214
|
except ValueError:
|
|
217
|
-
logger.warning(
|
|
218
|
-
f"アノテーション仕様の属性'{attribute_name}'に選択肢名(英語)が'{attribute_value}'である選択肢情報は存在しないか、複数存在します。 :: {log_message_suffix}" # noqa: E501
|
|
219
|
-
)
|
|
215
|
+
logger.warning(f"アノテーション仕様の属性'{attribute_name}'に選択肢名(英語)が'{attribute_value}'である選択肢情報は存在しないか、複数存在します。 :: {log_message_suffix}")
|
|
220
216
|
if self.is_strict:
|
|
221
217
|
raise
|
|
222
218
|
return None
|
|
@@ -226,9 +222,7 @@ class AnnotationConverter:
|
|
|
226
222
|
else:
|
|
227
223
|
assert_noreturn(additional_data_type)
|
|
228
224
|
|
|
229
|
-
def convert_attributes(
|
|
230
|
-
self, attributes: dict[str, Any], *, label_name: Optional[str] = None, log_message_suffix: str = ""
|
|
231
|
-
) -> list[dict[str, Any]]:
|
|
225
|
+
def convert_attributes(self, attributes: dict[str, Any], *, label_name: Optional[str] = None, log_message_suffix: str = "") -> list[dict[str, Any]]:
|
|
232
226
|
"""
|
|
233
227
|
インポート対象のアノテーションJSONに格納されている`attributes`を`AdditionalDataListV2`のlistに変換します。
|
|
234
228
|
|
|
@@ -248,9 +242,7 @@ class AnnotationConverter:
|
|
|
248
242
|
try:
|
|
249
243
|
specs_additional_data = self.annotation_specs_accessor.get_attribute(attribute_name=attribute_name, label=label)
|
|
250
244
|
except ValueError:
|
|
251
|
-
logger.warning(
|
|
252
|
-
f"アノテーション仕様に属性名(英語)が'{attribute_name}'である属性情報が存在しないか、複数存在します。 :: {log_message_suffix}"
|
|
253
|
-
)
|
|
245
|
+
logger.warning(f"アノテーション仕様に属性名(英語)が'{attribute_name}'である属性情報が存在しないか、複数存在します。 :: {log_message_suffix}")
|
|
254
246
|
if self.is_strict:
|
|
255
247
|
raise
|
|
256
248
|
continue
|
|
@@ -293,16 +285,12 @@ class AnnotationConverter:
|
|
|
293
285
|
ValueError: 存在しないラベル名が指定された場合(`self.is_strict`がFalseでもraiseされる9
|
|
294
286
|
|
|
295
287
|
"""
|
|
296
|
-
log_message_suffix =
|
|
297
|
-
f"task_id='{parser.task_id}', input_data_id='{parser.input_data_id}', label_name='{detail.label}', annotation_id='{detail.annotation_id}'"
|
|
298
|
-
)
|
|
288
|
+
log_message_suffix = f"task_id='{parser.task_id}', input_data_id='{parser.input_data_id}', label_name='{detail.label}', annotation_id='{detail.annotation_id}'"
|
|
299
289
|
|
|
300
290
|
try:
|
|
301
291
|
label_info = self.annotation_specs_accessor.get_label(label_name=detail.label)
|
|
302
292
|
except ValueError:
|
|
303
|
-
logger.warning(
|
|
304
|
-
f"アノテーション仕様にラベル名(英語)が'{detail.label}'であるラベル情報が存在しないか、または複数存在します。 :: {log_message_suffix}"
|
|
305
|
-
)
|
|
293
|
+
logger.warning(f"アノテーション仕様にラベル名(英語)が'{detail.label}'であるラベル情報が存在しないか、または複数存在します。 :: {log_message_suffix}")
|
|
306
294
|
raise
|
|
307
295
|
|
|
308
296
|
if detail.attributes is not None:
|
|
@@ -349,7 +337,7 @@ class AnnotationConverter:
|
|
|
349
337
|
details: インポート対象のアノテーション情報
|
|
350
338
|
old_details: 既存のアノテーション情報。既存のアノテーション情報に加えて、インポート対象のアノテーションを登録するためのリクエストボディを作成します。
|
|
351
339
|
updated_datetime: 更新日時
|
|
352
|
-
"""
|
|
340
|
+
"""
|
|
353
341
|
old_dict_detail = {}
|
|
354
342
|
INDEX_KEY = "_index" # noqa: N806
|
|
355
343
|
for index, old_detail in enumerate(old_details):
|
|
@@ -362,7 +350,7 @@ class AnnotationConverter:
|
|
|
362
350
|
new_request_details: list[dict[str, Any]] = []
|
|
363
351
|
for detail in details:
|
|
364
352
|
try:
|
|
365
|
-
log_message_suffix = f"task_id='{parser.task_id}', input_data_id='{parser.input_data_id}', label_name='{detail.label}', annotation_id='{detail.annotation_id}'"
|
|
353
|
+
log_message_suffix = f"task_id='{parser.task_id}', input_data_id='{parser.input_data_id}', label_name='{detail.label}', annotation_id='{detail.annotation_id}'"
|
|
366
354
|
|
|
367
355
|
request_detail = self.convert_annotation_detail(parser, detail, log_message_suffix=log_message_suffix)
|
|
368
356
|
except Exception as e:
|
|
@@ -424,9 +412,7 @@ class ImportAnnotationMain(CommandLineWithConfirm):
|
|
|
424
412
|
|
|
425
413
|
simple_annotation: ImportedSimpleAnnotation = ImportedSimpleAnnotation.from_dict(parser.load_json())
|
|
426
414
|
if len(simple_annotation.details) == 0:
|
|
427
|
-
logger.debug(
|
|
428
|
-
f"task_id='{task_id}', input_data_id='{input_data_id}' :: インポート元にアノテーションデータがないため、アノテーションの登録をスキップします。" # noqa: E501
|
|
429
|
-
)
|
|
415
|
+
logger.debug(f"task_id='{task_id}', input_data_id='{input_data_id}' :: インポート元にアノテーションデータがないため、アノテーションの登録をスキップします。")
|
|
430
416
|
return False
|
|
431
417
|
|
|
432
418
|
input_data = self.service.wrapper.get_input_data_or_none(self.project_id, input_data_id)
|
|
@@ -446,13 +432,9 @@ class ImportAnnotationMain(CommandLineWithConfirm):
|
|
|
446
432
|
|
|
447
433
|
logger.info(f"task_id='{task_id}', input_data_id='{input_data_id}' :: {len(simple_annotation.details)} 件のアノテーションを登録します。")
|
|
448
434
|
if self.is_merge:
|
|
449
|
-
request_body = self.converter.convert_annotation_details(
|
|
450
|
-
parser, simple_annotation.details, old_details=old_annotation["details"], updated_datetime=old_annotation["updated_datetime"]
|
|
451
|
-
)
|
|
435
|
+
request_body = self.converter.convert_annotation_details(parser, simple_annotation.details, old_details=old_annotation["details"], updated_datetime=old_annotation["updated_datetime"])
|
|
452
436
|
else:
|
|
453
|
-
request_body = self.converter.convert_annotation_details(
|
|
454
|
-
parser, simple_annotation.details, old_details=[], updated_datetime=old_annotation["updated_datetime"]
|
|
455
|
-
)
|
|
437
|
+
request_body = self.converter.convert_annotation_details(parser, simple_annotation.details, old_details=[], updated_datetime=old_annotation["updated_datetime"])
|
|
456
438
|
|
|
457
439
|
self.service.api.put_annotation(self.project_id, task_id, input_data_id, request_body=request_body, query_params={"v": "2"})
|
|
458
440
|
return True
|
|
@@ -551,9 +533,7 @@ class ImportAnnotationMain(CommandLineWithConfirm):
|
|
|
551
533
|
target_task_ids: Optional[set[str]] = None,
|
|
552
534
|
parallelism: Optional[int] = None,
|
|
553
535
|
):
|
|
554
|
-
def get_iter_task_parser_from_task_ids(
|
|
555
|
-
_iter_task_parser: Iterator[SimpleAnnotationParserByTask], _target_task_ids: set[str]
|
|
556
|
-
) -> Iterator[SimpleAnnotationParserByTask]:
|
|
536
|
+
def get_iter_task_parser_from_task_ids(_iter_task_parser: Iterator[SimpleAnnotationParserByTask], _target_task_ids: set[str]) -> Iterator[SimpleAnnotationParserByTask]:
|
|
557
537
|
for task_parser in _iter_task_parser:
|
|
558
538
|
if task_parser.task_id in _target_task_ids:
|
|
559
539
|
_target_task_ids.remove(task_parser.task_id)
|
|
@@ -586,9 +566,7 @@ class ImportAnnotationMain(CommandLineWithConfirm):
|
|
|
586
566
|
task_count += 1
|
|
587
567
|
|
|
588
568
|
if target_task_ids is not None and len(tmp_target_task_ids) > 0:
|
|
589
|
-
logger.warning(
|
|
590
|
-
f"'--task_id'で指定したタスクの内 {len(tmp_target_task_ids)} 件は、インポート対象のアノテーションデータに含まれていません。 :: {tmp_target_task_ids}" # noqa: E501
|
|
591
|
-
)
|
|
569
|
+
logger.warning(f"'--task_id'で指定したタスクの内 {len(tmp_target_task_ids)} 件は、インポート対象のアノテーションデータに含まれていません。 :: {tmp_target_task_ids}")
|
|
592
570
|
|
|
593
571
|
logger.info(f"{success_count} / {task_count} 件のタスクに対してアノテーションをインポートしました。")
|
|
594
572
|
|
|
@@ -679,8 +657,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
679
657
|
"--annotation",
|
|
680
658
|
type=Path,
|
|
681
659
|
required=True,
|
|
682
|
-
help="Simpleアノテーションと同じフォルダ構成のzipファイル or
|
|
683
|
-
"タスクの状態が作業中/完了の場合はインポートしません。",
|
|
660
|
+
help="Simpleアノテーションと同じフォルダ構成のzipファイル or ディレクトリのパスを指定してください。タスクの状態が作業中/完了の場合はインポートしません。",
|
|
684
661
|
)
|
|
685
662
|
|
|
686
663
|
argument_parser.add_task_id(required=False)
|
|
@@ -690,8 +667,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
690
667
|
overwrite_merge_group.add_argument(
|
|
691
668
|
"--overwrite",
|
|
692
669
|
action="store_true",
|
|
693
|
-
help="アノテーションが存在する場合、 ``--overwrite``
|
|
694
|
-
"指定しなければ、アノテーションのインポートをスキップします。",
|
|
670
|
+
help="アノテーションが存在する場合、 ``--overwrite`` を指定していれば、すでに存在するアノテーションを削除してインポートします。指定しなければ、アノテーションのインポートをスキップします。",
|
|
695
671
|
)
|
|
696
672
|
|
|
697
673
|
overwrite_merge_group.add_argument(
|
|
@@ -104,9 +104,7 @@ class ListAnnotationMain:
|
|
|
104
104
|
|
|
105
105
|
logger.debug(f"入力データ(input_data_id='{input_data_id}')のアノテーション一覧の件数: {len(annotation_list)}")
|
|
106
106
|
if len(annotation_list) == UPPER_BOUND:
|
|
107
|
-
logger.warning(
|
|
108
|
-
f"入力データ(input_data_id='{input_data_id}')のアノテーション一覧は{UPPER_BOUND}件で打ち切られている可能性があります。"
|
|
109
|
-
)
|
|
107
|
+
logger.warning(f"入力データ(input_data_id='{input_data_id}')のアノテーション一覧は{UPPER_BOUND}件で打ち切られている可能性があります。")
|
|
110
108
|
all_annotation_list.extend(annotation_list)
|
|
111
109
|
return all_annotation_list
|
|
112
110
|
else:
|
|
@@ -248,7 +246,6 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
248
246
|
choices=[FormatArgument.CSV, FormatArgument.JSON, FormatArgument.PRETTY_JSON],
|
|
249
247
|
default=FormatArgument.CSV,
|
|
250
248
|
)
|
|
251
|
-
argument_parser.add_csv_format()
|
|
252
249
|
|
|
253
250
|
argument_parser.add_output()
|
|
254
251
|
|
|
@@ -196,15 +196,10 @@ class MergeSegmentationMain(CommandLineWithConfirm):
|
|
|
196
196
|
return 0
|
|
197
197
|
|
|
198
198
|
if task["status"] in {TaskStatus.WORKING.value, TaskStatus.COMPLETE.value}:
|
|
199
|
-
logger.debug(
|
|
200
|
-
f"{log_message_prefix}task_id='{task_id}'のタスクの状態は「作業中」または「完了」であるため、"
|
|
201
|
-
f"アノテーションの更新をスキップします。 :: status='{task['status']}'"
|
|
202
|
-
)
|
|
199
|
+
logger.debug(f"{log_message_prefix}task_id='{task_id}'のタスクの状態は「作業中」または「完了」であるため、アノテーションの更新をスキップします。 :: status='{task['status']}'")
|
|
203
200
|
return 0
|
|
204
201
|
|
|
205
|
-
if not self.confirm_processing(
|
|
206
|
-
f"task_id='{task_id}'の次のラベル名に対応する複数の塗りつぶしアノテーションを1つにまとめますか? :: {self.label_names}"
|
|
207
|
-
):
|
|
202
|
+
if not self.confirm_processing(f"task_id='{task_id}'の次のラベル名に対応する複数の塗りつぶしアノテーションを1つにまとめますか? :: {self.label_names}"):
|
|
208
203
|
return 0
|
|
209
204
|
|
|
210
205
|
# 担当者割り当て変更チェック
|
|
@@ -235,16 +230,12 @@ class MergeSegmentationMain(CommandLineWithConfirm):
|
|
|
235
230
|
if result:
|
|
236
231
|
success_input_data_count += 1
|
|
237
232
|
except Exception:
|
|
238
|
-
logger.warning(
|
|
239
|
-
f"{log_message_prefix}task_id='{task_id}', input_data_id='{input_data_id}'のアノテーションの更新に失敗しました。", exc_info=True
|
|
240
|
-
)
|
|
233
|
+
logger.warning(f"{log_message_prefix}task_id='{task_id}', input_data_id='{input_data_id}'のアノテーションの更新に失敗しました。", exc_info=True)
|
|
241
234
|
continue
|
|
242
235
|
|
|
243
236
|
# 担当者を元に戻す
|
|
244
237
|
if changed_operator:
|
|
245
|
-
logger.debug(
|
|
246
|
-
f"{log_message_prefix}task_id='{task_id}' のタスクの担当者を、元の担当者(account_id='{original_operator_account_id}')に変更します。"
|
|
247
|
-
)
|
|
238
|
+
logger.debug(f"{log_message_prefix}task_id='{task_id}' のタスクの担当者を、元の担当者(account_id='{original_operator_account_id}')に変更します。")
|
|
248
239
|
self.annofab_service.wrapper.change_task_operator(
|
|
249
240
|
self.project_id,
|
|
250
241
|
task_id,
|
|
@@ -328,8 +319,7 @@ class MergeSegmentation(CommandLine):
|
|
|
328
319
|
|
|
329
320
|
if len(invalid_label_name_list) > 0:
|
|
330
321
|
print( # noqa: T201
|
|
331
|
-
f"{self.COMMON_MESSAGE} --label_name: 次のラベル名(英語)
|
|
332
|
-
f"アノテーションの種類が「塗りつぶし」ではありません。 :: {invalid_label_name_list}",
|
|
322
|
+
f"{self.COMMON_MESSAGE} --label_name: 次のラベル名(英語)はアノテーション仕様に存在しないか、アノテーションの種類が「塗りつぶし」ではありません。 :: {invalid_label_name_list}",
|
|
333
323
|
file=sys.stderr,
|
|
334
324
|
)
|
|
335
325
|
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|