annofabcli 1.100.0__py3-none-any.whl → 100.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- annofabcli/__version__.py +1 -1
- annofabcli/annotation/change_annotation_attributes.py +2 -2
- annofabcli/annotation_specs/list_annotation_specs_attribute.py +51 -33
- annofabcli/annotation_specs/list_annotation_specs_choice.py +42 -17
- annofabcli/annotation_specs/list_annotation_specs_label.py +26 -93
- annofabcli/annotation_specs/list_annotation_specs_label_attribute.py +220 -0
- annofabcli/annotation_specs/subcommand_annotation_specs.py +2 -0
- annofabcli/common/annofab/annotation_specs.py +25 -0
- annofabcli/common/download.py +1 -1
- annofabcli/common/exceptions.py +2 -2
- annofabcli/common/facade.py +2 -2
- annofabcli/common/image.py +2 -2
- annofabcli/input_data/delete_input_data.py +6 -7
- annofabcli/job/delete_job.py +4 -4
- annofabcli/organization_member/list_organization_member.py +2 -3
- annofabcli/project_member/change_project_members.py +2 -3
- annofabcli/project_member/drop_project_members.py +8 -8
- annofabcli/project_member/invite_project_members.py +5 -6
- annofabcli/project_member/list_users.py +4 -4
- annofabcli/task/complete_tasks.py +2 -2
- annofabcli/task/reject_tasks.py +76 -100
- annofabcli/task/update_metadata_of_task.py +1 -1
- annofabcli/task_history/list_task_history.py +1 -1
- {annofabcli-1.100.0.dist-info → annofabcli-100.2.dist-info}/METADATA +1 -1
- {annofabcli-1.100.0.dist-info → annofabcli-100.2.dist-info}/RECORD +28 -26
- {annofabcli-1.100.0.dist-info → annofabcli-100.2.dist-info}/LICENSE +0 -0
- {annofabcli-1.100.0.dist-info → annofabcli-100.2.dist-info}/WHEEL +0 -0
- {annofabcli-1.100.0.dist-info → annofabcli-100.2.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import sys
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Optional
|
|
10
|
+
|
|
11
|
+
import pandas
|
|
12
|
+
from annofabapi.models import Lang
|
|
13
|
+
from annofabapi.util.annotation_specs import get_message_with_lang
|
|
14
|
+
from dataclasses_json import DataClassJsonMixin
|
|
15
|
+
|
|
16
|
+
import annofabcli
|
|
17
|
+
import annofabcli.common.cli
|
|
18
|
+
from annofabcli.common.cli import (
|
|
19
|
+
COMMAND_LINE_ERROR_STATUS_CODE,
|
|
20
|
+
ArgumentParser,
|
|
21
|
+
CommandLine,
|
|
22
|
+
build_annofabapi_resource_and_login,
|
|
23
|
+
)
|
|
24
|
+
from annofabcli.common.enums import FormatArgument
|
|
25
|
+
from annofabcli.common.facade import AnnofabApiFacade
|
|
26
|
+
from annofabcli.common.utils import print_according_to_format, print_csv
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class LabelAndAttribute(DataClassJsonMixin):
|
|
33
|
+
label_id: str
|
|
34
|
+
label_name_en: Optional[str]
|
|
35
|
+
label_name_ja: Optional[str]
|
|
36
|
+
label_name_vi: Optional[str]
|
|
37
|
+
annotation_type: str
|
|
38
|
+
|
|
39
|
+
attribute_id: str
|
|
40
|
+
"""属性ID
|
|
41
|
+
|
|
42
|
+
Notes:
|
|
43
|
+
APIレスポンスの ``additional_data_definition_id`` に相当します。
|
|
44
|
+
``additional_data_definition_id`` という名前がアノテーションJSONの `attributes` と対応していることが分かりにくかったので、`attribute_id`という名前に変えました。
|
|
45
|
+
""" # noqa: E501
|
|
46
|
+
attribute_name_en: Optional[str]
|
|
47
|
+
attribute_name_ja: Optional[str]
|
|
48
|
+
attribute_name_vi: Optional[str]
|
|
49
|
+
attribute_type: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def create_label_attribute_list(labels_v3: list[dict[str, Any]], additionals_v3: list[dict[str, Any]]) -> list[LabelAndAttribute]:
|
|
53
|
+
"""
|
|
54
|
+
APIから取得したラベル情報(v3版)から、`LabelAndAttribute`のlistを生成します。
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
labels_v3: APIから取得したラベル情報(v3版)
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def to_dataclass_list(label: dict[str, Any]) -> list[LabelAndAttribute]:
|
|
61
|
+
result = []
|
|
62
|
+
for attribute_id in label["additional_data_definitions"]:
|
|
63
|
+
attribute = dict_attributes[attribute_id]
|
|
64
|
+
|
|
65
|
+
result.append(
|
|
66
|
+
LabelAndAttribute(
|
|
67
|
+
label_id=label["label_id"],
|
|
68
|
+
label_name_en=get_message_with_lang(label["label_name"], lang=Lang.EN_US),
|
|
69
|
+
label_name_ja=get_message_with_lang(label["label_name"], lang=Lang.JA_JP),
|
|
70
|
+
label_name_vi=get_message_with_lang(label["label_name"], lang=Lang.VI_VN),
|
|
71
|
+
annotation_type=label["annotation_type"],
|
|
72
|
+
attribute_id=attribute_id,
|
|
73
|
+
attribute_name_en=get_message_with_lang(attribute["name"], lang=Lang.EN_US),
|
|
74
|
+
attribute_name_ja=get_message_with_lang(attribute["name"], lang=Lang.JA_JP),
|
|
75
|
+
attribute_name_vi=get_message_with_lang(attribute["name"], lang=Lang.VI_VN),
|
|
76
|
+
attribute_type=attribute["type"],
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
return result
|
|
80
|
+
|
|
81
|
+
dict_attributes = {}
|
|
82
|
+
for elm in additionals_v3:
|
|
83
|
+
dict_attributes[elm["additional_data_definition_id"]] = elm
|
|
84
|
+
|
|
85
|
+
result = []
|
|
86
|
+
for label in labels_v3:
|
|
87
|
+
result.extend(to_dataclass_list(label))
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class PrintAnnotationSpecsLabelAndAttribute(CommandLine):
|
|
92
|
+
COMMON_MESSAGE = "annofabcli annotation_specs list_label: error:"
|
|
93
|
+
|
|
94
|
+
def print_annotation_specs_label(self, annotation_specs_v3: dict[str, Any], output_format: FormatArgument, output: Optional[str] = None) -> None:
|
|
95
|
+
# アノテーション仕様のv2とv3はほとんど同じなので、`convert_annotation_specs_labels_v2_to_v1`にはV3のアノテーション仕様を渡す
|
|
96
|
+
label_attribute_list = create_label_attribute_list(annotation_specs_v3["labels"], annotation_specs_v3["additionals"])
|
|
97
|
+
|
|
98
|
+
if output_format == FormatArgument.CSV:
|
|
99
|
+
columns = [
|
|
100
|
+
"label_id",
|
|
101
|
+
"label_name_en",
|
|
102
|
+
"label_name_ja",
|
|
103
|
+
"label_name_vi",
|
|
104
|
+
"annotation_type",
|
|
105
|
+
"attribute_id",
|
|
106
|
+
"attribute_name_en",
|
|
107
|
+
"attribute_name_ja",
|
|
108
|
+
"attribute_name_vi",
|
|
109
|
+
"attribute_type",
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
df = pandas.DataFrame(label_attribute_list, columns=columns)
|
|
113
|
+
print_csv(df, output)
|
|
114
|
+
|
|
115
|
+
elif output_format in [FormatArgument.JSON, FormatArgument.PRETTY_JSON]:
|
|
116
|
+
print_according_to_format([e.to_dict() for e in label_attribute_list], format=output_format, output=output)
|
|
117
|
+
|
|
118
|
+
def get_history_id_from_before_index(self, project_id: str, before: int) -> Optional[str]:
|
|
119
|
+
histories, _ = self.service.api.get_annotation_specs_histories(project_id)
|
|
120
|
+
if before + 1 > len(histories):
|
|
121
|
+
logger.warning(f"アノテーション仕様の履歴は{len(histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。")
|
|
122
|
+
return None
|
|
123
|
+
history = histories[-(before + 1)]
|
|
124
|
+
logger.info(
|
|
125
|
+
f"{history['updated_datetime']}のアノテーション仕様を出力します。history_id={history['history_id']}, comment={history['comment']}"
|
|
126
|
+
)
|
|
127
|
+
return history["history_id"]
|
|
128
|
+
|
|
129
|
+
def main(self) -> None:
|
|
130
|
+
args = self.args
|
|
131
|
+
|
|
132
|
+
if args.project_id is not None:
|
|
133
|
+
if args.before is not None:
|
|
134
|
+
history_id = self.get_history_id_from_before_index(args.project_id, args.before)
|
|
135
|
+
if history_id is None:
|
|
136
|
+
print( # noqa: T201
|
|
137
|
+
f"{self.COMMON_MESSAGE} argument --before: 最新より{args.before}個前のアノテーション仕様は見つかりませんでした。",
|
|
138
|
+
file=sys.stderr,
|
|
139
|
+
)
|
|
140
|
+
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|
|
141
|
+
else:
|
|
142
|
+
# args.beforeがNoneならば、必ずargs.history_idはNoneでない
|
|
143
|
+
history_id = args.history_id
|
|
144
|
+
|
|
145
|
+
annotation_specs, _ = self.service.api.get_annotation_specs(args.project_id, query_params={"history_id": history_id, "v": "3"})
|
|
146
|
+
|
|
147
|
+
elif args.annotation_specs_json is not None:
|
|
148
|
+
with args.annotation_specs_json.open() as f:
|
|
149
|
+
annotation_specs = json.load(f)
|
|
150
|
+
|
|
151
|
+
else:
|
|
152
|
+
raise RuntimeError("'--project_id'か'--annotation_specs_json'のどちらかを指定する必要があります。")
|
|
153
|
+
|
|
154
|
+
self.print_annotation_specs_label(annotation_specs, output_format=FormatArgument(args.format), output=args.output)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
158
|
+
argument_parser = ArgumentParser(parser)
|
|
159
|
+
|
|
160
|
+
required_group = parser.add_mutually_exclusive_group(required=True)
|
|
161
|
+
required_group.add_argument(
|
|
162
|
+
"-p", "--project_id", help="対象のプロジェクトのproject_idを指定します。APIで取得したアノテーション仕様情報を元に出力します。"
|
|
163
|
+
)
|
|
164
|
+
required_group.add_argument(
|
|
165
|
+
"--annotation_specs_json",
|
|
166
|
+
type=Path,
|
|
167
|
+
help="指定したアノテーション仕様のJSONファイルを指定します。"
|
|
168
|
+
"JSONファイルに記載された情報を元に出力します。ただしアノテーション仕様の ``format_version`` は ``3`` である必要があります。",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# 過去のアノテーション仕様を参照するためのオプション
|
|
172
|
+
old_annotation_specs_group = parser.add_mutually_exclusive_group()
|
|
173
|
+
old_annotation_specs_group.add_argument(
|
|
174
|
+
"--history_id",
|
|
175
|
+
type=str,
|
|
176
|
+
help=(
|
|
177
|
+
"出力したいアノテーション仕様のhistory_idを指定してください。 "
|
|
178
|
+
"history_idは ``annotation_specs list_history`` コマンドで確認できます。 "
|
|
179
|
+
"指定しない場合は、最新のアノテーション仕様が出力されます。 "
|
|
180
|
+
),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
old_annotation_specs_group.add_argument(
|
|
184
|
+
"--before",
|
|
185
|
+
type=int,
|
|
186
|
+
help=(
|
|
187
|
+
"出力したい過去のアノテーション仕様が、最新よりいくつ前のアノテーション仕様であるかを指定してください。 "
|
|
188
|
+
"たとえば ``1`` を指定した場合、最新より1個前のアノテーション仕様を出力します。 "
|
|
189
|
+
"指定しない場合は、最新のアノテーション仕様が出力されます。 "
|
|
190
|
+
),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
parser.add_argument(
|
|
194
|
+
"-f",
|
|
195
|
+
"--format",
|
|
196
|
+
type=str,
|
|
197
|
+
choices=[FormatArgument.CSV.value, FormatArgument.JSON.value, FormatArgument.PRETTY_JSON.value],
|
|
198
|
+
default=FormatArgument.CSV.value,
|
|
199
|
+
help="出力フォーマット ",
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
argument_parser.add_output()
|
|
203
|
+
|
|
204
|
+
parser.set_defaults(subcommand_func=main)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def main(args: argparse.Namespace) -> None:
|
|
208
|
+
service = build_annofabapi_resource_and_login(args)
|
|
209
|
+
facade = AnnofabApiFacade(service)
|
|
210
|
+
PrintAnnotationSpecsLabelAndAttribute(service, facade, args).main()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
|
|
214
|
+
subcommand_name = "list_label_attribute"
|
|
215
|
+
|
|
216
|
+
subcommand_help = "アノテーション仕様のラベルとラベルに含まれている属性の一覧を出力します。"
|
|
217
|
+
|
|
218
|
+
parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help)
|
|
219
|
+
parse_args(parser)
|
|
220
|
+
return parser
|
|
@@ -11,6 +11,7 @@ import annofabcli.annotation_specs.list_annotation_specs_attribute
|
|
|
11
11
|
import annofabcli.annotation_specs.list_annotation_specs_choice
|
|
12
12
|
import annofabcli.annotation_specs.list_annotation_specs_history
|
|
13
13
|
import annofabcli.annotation_specs.list_annotation_specs_label
|
|
14
|
+
import annofabcli.annotation_specs.list_annotation_specs_label_attribute
|
|
14
15
|
import annofabcli.annotation_specs.list_attribute_restriction
|
|
15
16
|
import annofabcli.annotation_specs.list_label_color
|
|
16
17
|
import annofabcli.annotation_specs.put_label_color
|
|
@@ -31,6 +32,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
31
32
|
annofabcli.annotation_specs.list_annotation_specs_choice.add_parser(subparsers)
|
|
32
33
|
annofabcli.annotation_specs.list_annotation_specs_history.add_parser(subparsers)
|
|
33
34
|
annofabcli.annotation_specs.list_annotation_specs_label.add_parser(subparsers)
|
|
35
|
+
annofabcli.annotation_specs.list_annotation_specs_label_attribute.add_parser(subparsers)
|
|
34
36
|
annofabcli.annotation_specs.list_label_color.add_parser(subparsers)
|
|
35
37
|
annofabcli.annotation_specs.put_label_color.add_parser(subparsers)
|
|
36
38
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def keybind_to_text(keybind: list[dict[str, Any]]) -> str:
|
|
5
|
+
"""
|
|
6
|
+
以下の構造を持つkeybindを、人が読める形式に変換します。
|
|
7
|
+
{"alt": False, "code": "Numpad1", "ctrl": False, "shift": False}
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def to_str(one_keybind: dict[str, Any]) -> str:
|
|
11
|
+
keys = []
|
|
12
|
+
if one_keybind.get("ctrl", False):
|
|
13
|
+
keys.append("Ctrl")
|
|
14
|
+
if one_keybind.get("alt", False):
|
|
15
|
+
keys.append("Alt")
|
|
16
|
+
if one_keybind.get("shift", False):
|
|
17
|
+
keys.append("Shift")
|
|
18
|
+
code = one_keybind.get("code", "")
|
|
19
|
+
assert code is not None
|
|
20
|
+
|
|
21
|
+
keys.append(f"{code}")
|
|
22
|
+
return "+".join(keys)
|
|
23
|
+
|
|
24
|
+
tmp_list = [to_str(elm) for elm in keybind]
|
|
25
|
+
return ",".join(tmp_list)
|
annofabcli/common/download.py
CHANGED
|
@@ -50,7 +50,7 @@ class DownloadingFile:
|
|
|
50
50
|
|
|
51
51
|
max_wait_minutes = self.get_max_wait_minutes(wait_options)
|
|
52
52
|
filetype = DOWNLOADING_FILETYPE_DICT[job_type]
|
|
53
|
-
logger.info(f"{filetype}の更新処理が完了するまで、最大{max_wait_minutes}分間待ちます。job_id={job_id}")
|
|
53
|
+
logger.info(f"{filetype}の更新処理が完了するまで、最大{max_wait_minutes}分間待ちます。job_id='{job_id}'")
|
|
54
54
|
result = self.service.wrapper.wait_for_completion(
|
|
55
55
|
project_id,
|
|
56
56
|
job_type=job_type,
|
annofabcli/common/exceptions.py
CHANGED
|
@@ -46,7 +46,7 @@ class ProjectAuthorizationError(AuthorizationError):
|
|
|
46
46
|
|
|
47
47
|
def __init__(self, project_title: str, roles: list[ProjectMemberRole]) -> None:
|
|
48
48
|
role_values = [e.value for e in roles]
|
|
49
|
-
msg = f"
|
|
49
|
+
msg = f"プロジェクト'{project_title}'に対して、ロール'{role_values}'のいずれかが必要です。"
|
|
50
50
|
super().__init__(msg)
|
|
51
51
|
|
|
52
52
|
|
|
@@ -57,7 +57,7 @@ class OrganizationAuthorizationError(AuthorizationError):
|
|
|
57
57
|
|
|
58
58
|
def __init__(self, organization_name: str, roles: list[OrganizationMemberRole]) -> None:
|
|
59
59
|
role_values = [e.value for e in roles]
|
|
60
|
-
msg = f"
|
|
60
|
+
msg = f"組織'{organization_name}'に対して、ロール'{role_values}'のいずれかが必要です。"
|
|
61
61
|
super().__init__(msg)
|
|
62
62
|
|
|
63
63
|
|
annofabcli/common/facade.py
CHANGED
|
@@ -499,12 +499,12 @@ class AnnofabApiFacade:
|
|
|
499
499
|
task_query.account_id = self.get_account_id_from_user_id(project_id, task_query.user_id)
|
|
500
500
|
return task_query
|
|
501
501
|
|
|
502
|
-
def validate_project(
|
|
502
|
+
def validate_project(
|
|
503
503
|
self,
|
|
504
504
|
project_id: str,
|
|
505
505
|
project_member_roles: Optional[list[ProjectMemberRole]] = None,
|
|
506
506
|
organization_member_roles: Optional[list[OrganizationMemberRole]] = None,
|
|
507
|
-
):
|
|
507
|
+
) -> None:
|
|
508
508
|
"""
|
|
509
509
|
プロジェクト or 組織に対して、必要な権限が付与されているかを確認する。
|
|
510
510
|
|
annofabcli/common/image.py
CHANGED
|
@@ -85,7 +85,7 @@ def fill_annotation(
|
|
|
85
85
|
if outer_image is not None:
|
|
86
86
|
draw.bitmap([0, 0], outer_image, fill=color)
|
|
87
87
|
else:
|
|
88
|
-
logger.warning(f"アノテーション種類が`{data_type}`ですが、`outer_image`がNoneです。 annotation_id={annotation.annotation_id}")
|
|
88
|
+
logger.warning(f"アノテーション種類が`{data_type}`ですが、`outer_image`がNoneです。 annotation_id='{annotation.annotation_id}'")
|
|
89
89
|
|
|
90
90
|
return draw
|
|
91
91
|
|
|
@@ -344,7 +344,7 @@ def write_annotation_images_from_path(
|
|
|
344
344
|
output_image_file = output_dir_path / f"{Path(parser.json_file_path).stem}.{output_image_extension}"
|
|
345
345
|
tmp_image_size = _get_image_size(parser.input_data_id)
|
|
346
346
|
if tmp_image_size is None:
|
|
347
|
-
logger.warning(f"task_id={parser.task_id}, input_data_id={parser.input_data_id}: 画像サイズを取得できなかったので、スキップします。")
|
|
347
|
+
logger.warning(f"task_id='{parser.task_id}', input_data_id='{parser.input_data_id}': 画像サイズを取得できなかったので、スキップします。")
|
|
348
348
|
continue
|
|
349
349
|
|
|
350
350
|
write_annotation_image(
|
|
@@ -42,11 +42,11 @@ class DeleteInputData(CommandLine):
|
|
|
42
42
|
f"supplementary_data_name={supplementary_data['supplementary_data_name']}"
|
|
43
43
|
)
|
|
44
44
|
deleted_count += 1
|
|
45
|
-
except requests.HTTPError
|
|
46
|
-
logger.warning(e)
|
|
45
|
+
except requests.HTTPError:
|
|
47
46
|
logger.warning(
|
|
48
47
|
f"補助情報の削除に失敗しました。input_data_id={input_data_id}, supplementary_data_id={supplementary_data_id}, "
|
|
49
|
-
f"supplementary_data_name={supplementary_data['supplementary_data_name']}"
|
|
48
|
+
f"supplementary_data_name={supplementary_data['supplementary_data_name']}",
|
|
49
|
+
exc_info=True,
|
|
50
50
|
)
|
|
51
51
|
continue
|
|
52
52
|
|
|
@@ -69,7 +69,7 @@ class DeleteInputData(CommandLine):
|
|
|
69
69
|
def delete_input_data(self, project_id: str, input_data_id: str, input_data_index: int, delete_supplementary: bool, force: bool): # noqa: ANN201, FBT001
|
|
70
70
|
input_data = self.service.wrapper.get_input_data_or_none(project_id, input_data_id)
|
|
71
71
|
if input_data is None:
|
|
72
|
-
logger.info(f"input_data_id={input_data_id}
|
|
72
|
+
logger.info(f"input_data_id='{input_data_id}'である入力データは存在しません。")
|
|
73
73
|
return False
|
|
74
74
|
|
|
75
75
|
task_list = self.service.wrapper.get_all_tasks(project_id, query_params={"input_data_ids": input_data_id})
|
|
@@ -137,9 +137,8 @@ class DeleteInputData(CommandLine):
|
|
|
137
137
|
if result:
|
|
138
138
|
count_delete_input_data += 1
|
|
139
139
|
|
|
140
|
-
except requests.exceptions.HTTPError
|
|
141
|
-
logger.warning(
|
|
142
|
-
logger.warning(f"input_data_id='{input_data_id}'の削除に失敗しました。")
|
|
140
|
+
except requests.exceptions.HTTPError:
|
|
141
|
+
logger.warning(f"input_data_id='{input_data_id}'である入力データの削除に失敗しました。", exc_info=True)
|
|
143
142
|
continue
|
|
144
143
|
|
|
145
144
|
logger.info(f"プロジェクト'{project_title}'から 、{count_delete_input_data}/{len(input_data_id_list)} 件の入力データを削除しました。")
|
annofabcli/job/delete_job.py
CHANGED
|
@@ -29,14 +29,14 @@ class DeleteJobMain:
|
|
|
29
29
|
count = 0
|
|
30
30
|
for job_id in job_id_list:
|
|
31
31
|
if job_id not in exists_job_id_set:
|
|
32
|
-
logger.debug(f"job_id={job_id} のジョブは存在しなかったのでスキップします。")
|
|
32
|
+
logger.debug(f"job_id='{job_id}' のジョブは存在しなかったのでスキップします。")
|
|
33
33
|
continue
|
|
34
34
|
try:
|
|
35
35
|
self.service.api.delete_project_job(project_id, job_type.value, job_id)
|
|
36
|
-
logger.debug(f"job_type={job_type.value}, job_id={job_id} のジョブを削除しました。")
|
|
36
|
+
logger.debug(f"job_type={job_type.value}, job_id='{job_id}' のジョブを削除しました。")
|
|
37
37
|
count += 1
|
|
38
|
-
except Exception
|
|
39
|
-
logger.warning(
|
|
38
|
+
except Exception: # pylint: disable=broad-except
|
|
39
|
+
logger.warning(f"job_type={job_type.value}, job_id='{job_id}' のジョブの削除に失敗しました。", exc_info=True)
|
|
40
40
|
logger.info(f"{count} / {len(job_id_list)} 件のジョブを削除しました。")
|
|
41
41
|
|
|
42
42
|
|
|
@@ -48,9 +48,8 @@ class ListOrganizationMember(CommandLine):
|
|
|
48
48
|
for organization_name in organization_name_list:
|
|
49
49
|
try:
|
|
50
50
|
organization_member_list.extend(self.get_organization_member_list(organization_name))
|
|
51
|
-
except requests.HTTPError
|
|
52
|
-
logger.warning(
|
|
53
|
-
logger.warning(f"{organization_name} の組織メンバを取得できませんでした。")
|
|
51
|
+
except requests.HTTPError:
|
|
52
|
+
logger.warning(f"組織'{organization_name}'のメンバー一覧を取得できませんでした。", exc_info=True)
|
|
54
53
|
continue
|
|
55
54
|
|
|
56
55
|
if args.format == FormatArgument.CSV.value:
|
|
@@ -115,9 +115,8 @@ class ChangeProjectMembers(CommandLine):
|
|
|
115
115
|
logger.debug(f"user_id = {user_id} のプロジェクトメンバ情報を変更しました。member_role={member_role}, member_info={member_info}")
|
|
116
116
|
count_invite_members += 1
|
|
117
117
|
|
|
118
|
-
except requests.exceptions.HTTPError
|
|
119
|
-
logger.warning(
|
|
120
|
-
logger.warning(f"プロジェクトメンバの登録に失敗しました。user_id={user_id}")
|
|
118
|
+
except requests.exceptions.HTTPError:
|
|
119
|
+
logger.warning(f"プロジェクトメンバの登録に失敗しました。 :: user_id='{user_id}'", exc_info=True)
|
|
121
120
|
|
|
122
121
|
logger.info(f"{project_title} に、{count_invite_members} / {len(user_id_list)} 件のプロジェクトメンバを変更しました。")
|
|
123
122
|
|
|
@@ -49,10 +49,11 @@ class DropProjectMembersMain:
|
|
|
49
49
|
}
|
|
50
50
|
try:
|
|
51
51
|
self.service.api.put_project_member(project_id, user_id, request_body=request_body)
|
|
52
|
-
logger.debug(f"{project_title}({project_id})
|
|
53
|
-
except requests.HTTPError
|
|
54
|
-
logger.warning(
|
|
55
|
-
|
|
52
|
+
logger.debug(f"プロジェクト'{project_title}'(project_id='{project_id}') から、user_id='{user_id}'のユーザーを脱退させました。")
|
|
53
|
+
except requests.HTTPError:
|
|
54
|
+
logger.warning(
|
|
55
|
+
f"プロジェクト'{project_title}'(project_id='{project_id}') から、user_id='{user_id}'のユーザーを脱退させられませんでした。"
|
|
56
|
+
)
|
|
56
57
|
|
|
57
58
|
def drop_role_with_organization(self, organization_name: str, user_id_list: list[str]): # noqa: ANN201
|
|
58
59
|
projects = self.service.wrapper.get_all_projects_of_organization(organization_name, query_params={"account_id": self.service.api.account_id})
|
|
@@ -64,14 +65,13 @@ class DropProjectMembersMain:
|
|
|
64
65
|
for project_id in project_id_list:
|
|
65
66
|
try:
|
|
66
67
|
if not self.facade.my_role_is_owner(project_id):
|
|
67
|
-
logger.warning(f"オーナではないため、プロジェクトメンバを脱退させられません。project_id
|
|
68
|
+
logger.warning(f"オーナではないため、プロジェクトメンバを脱退させられません。 :: project_id='{project_id}'")
|
|
68
69
|
continue
|
|
69
70
|
|
|
70
71
|
self.drop_project_members(project_id, user_id_list)
|
|
71
72
|
|
|
72
|
-
except requests.HTTPError
|
|
73
|
-
logger.warning(
|
|
74
|
-
logger.warning(f"project_id={project_id} のプロジェクトメンバからユーザを脱退させられませんでした。")
|
|
73
|
+
except requests.HTTPError:
|
|
74
|
+
logger.warning(f"project_id='{project_id}' のプロジェクトメンバからユーザを脱退させられませんでした。", exc_info=True)
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
class DropProjectMembers(CommandLine):
|
|
@@ -55,10 +55,10 @@ class InviteProjectMemberMain:
|
|
|
55
55
|
try:
|
|
56
56
|
self.service.api.put_project_member(project_id, user_id, request_body=request_body)
|
|
57
57
|
logger.debug(f"{project_title}({project_id}) のプロジェクトメンバに、{user_id} を {member_role.value} ロールで追加しました。")
|
|
58
|
-
except requests.HTTPError
|
|
59
|
-
logger.warning(e)
|
|
58
|
+
except requests.HTTPError:
|
|
60
59
|
logger.warning(
|
|
61
|
-
f"{project_title}({project_id}) のプロジェクトメンバに、{user_id} を {member_role.value} ロールで追加できませんでした。"
|
|
60
|
+
f"{project_title}({project_id}) のプロジェクトメンバに、{user_id} を {member_role.value} ロールで追加できませんでした。",
|
|
61
|
+
exc_info=True,
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
def assign_role_with_organization(self, organization_name: str, user_id_list: list[str], member_role: ProjectMemberRole): # noqa: ANN201
|
|
@@ -75,9 +75,8 @@ class InviteProjectMemberMain:
|
|
|
75
75
|
|
|
76
76
|
self.invite_project_members(project_id, user_id_list, member_role)
|
|
77
77
|
|
|
78
|
-
except requests.HTTPError
|
|
79
|
-
logger.warning(
|
|
80
|
-
logger.warning(f"project_id={project_id} のプロジェクトメンバにユーザを招待できませんでした。")
|
|
78
|
+
except requests.HTTPError:
|
|
79
|
+
logger.warning(f"project_id='{project_id}' のプロジェクトメンバにユーザを招待できませんでした。")
|
|
81
80
|
|
|
82
81
|
|
|
83
82
|
class InviteUser(CommandLine):
|
|
@@ -48,16 +48,16 @@ class ListUser(CommandLine):
|
|
|
48
48
|
for project_id in project_id_list:
|
|
49
49
|
try:
|
|
50
50
|
project, _ = self.service.api.get_project(project_id)
|
|
51
|
-
except requests.exceptions.HTTPError
|
|
52
|
-
logger.warning(e)
|
|
51
|
+
except requests.exceptions.HTTPError:
|
|
53
52
|
logger.warning(
|
|
54
|
-
f"project_id
|
|
53
|
+
f"project_id='{project_id}' のプロジェクトにアクセスできなかった(存在しないproject_id、またはプロジェクトメンバでない)",
|
|
54
|
+
exc_info=True,
|
|
55
55
|
)
|
|
56
56
|
continue
|
|
57
57
|
|
|
58
58
|
project_title = project["title"]
|
|
59
59
|
project_members = self.get_all_project_members(project_id, include_inactive=include_inactive)
|
|
60
|
-
logger.info(f"{project_title} のプロジェクトメンバを {len(project_members)} 件取得した。project_id={project_id}")
|
|
60
|
+
logger.info(f"{project_title} のプロジェクトメンバを {len(project_members)} 件取得した。project_id='{project_id}'")
|
|
61
61
|
|
|
62
62
|
for member in project_members:
|
|
63
63
|
AddProps.add_properties_of_project(member, project_title)
|
|
@@ -76,7 +76,7 @@ class CompleteTasksMain(CommandLineWithConfirm):
|
|
|
76
76
|
comment_status: CommentStatus,
|
|
77
77
|
):
|
|
78
78
|
if comment_list is None or len(comment_list) == 0:
|
|
79
|
-
logger.warning(f"変更対象の検査コメントはなかった。task_id
|
|
79
|
+
logger.warning(f"変更対象の検査コメントはなかった。task_id='{task.task_id}', input_data_id='{input_data_id}'")
|
|
80
80
|
return
|
|
81
81
|
|
|
82
82
|
def to_req_inspection(comment: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -332,7 +332,7 @@ class CompleteTasksMain(CommandLineWithConfirm):
|
|
|
332
332
|
|
|
333
333
|
task: Task = Task.from_dict(dict_task)
|
|
334
334
|
logger.info(
|
|
335
|
-
f"{logging_prefix} : タスク情報 task_id={task_id}, phase={task.phase.value}, phase_stage={task.phase_stage}, status={task.status.value}"
|
|
335
|
+
f"{logging_prefix} : タスク情報 task_id='{task_id}', phase={task.phase.value}, phase_stage={task.phase_stage}, status={task.status.value}"
|
|
336
336
|
)
|
|
337
337
|
if not self._validate_task(task, target_phase=target_phase, target_phase_stage=target_phase_stage, task_query=task_query):
|
|
338
338
|
return False
|