annofabcli 1.114.5__py3-none-any.whl → 1.114.6__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/annotation_zip/list_annotation_3d_bounding_box.py +2 -2
- annofabcli/annotation_zip/list_annotation_bounding_box_2d.py +2 -2
- annofabcli/annotation_zip/list_polygon_annotation.py +2 -2
- annofabcli/annotation_zip/list_polyline_annotation.py +2 -2
- annofabcli/annotation_zip/list_range_annotation.py +2 -2
- annofabcli/annotation_zip/list_single_point_annotation.py +2 -2
- annofabcli/comment/delete_comment.py +2 -2
- annofabcli/comment/put_comment.py +145 -19
- annofabcli/comment/put_comment_simply.py +7 -4
- annofabcli/comment/put_inspection_comment.py +5 -1
- annofabcli/comment/put_onhold_comment.py +5 -1
- annofabcli/input_data/list_all_input_data_merged_task.py +3 -3
- annofabcli/statistics/list_annotation_count.py +4 -4
- annofabcli/statistics/list_annotation_duration.py +1 -1
- annofabcli/statistics/list_video_duration.py +1 -1
- {annofabcli-1.114.5.dist-info → annofabcli-1.114.6.dist-info}/METADATA +1 -1
- {annofabcli-1.114.5.dist-info → annofabcli-1.114.6.dist-info}/RECORD +20 -20
- {annofabcli-1.114.5.dist-info → annofabcli-1.114.6.dist-info}/WHEEL +0 -0
- {annofabcli-1.114.5.dist-info → annofabcli-1.114.6.dist-info}/entry_points.txt +0 -0
- {annofabcli-1.114.5.dist-info → annofabcli-1.114.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -32,9 +32,9 @@ logger = logging.getLogger(__name__)
|
|
|
32
32
|
class Annotation3DBoundingBoxInfo(DataClassJsonMixin):
|
|
33
33
|
project_id: str
|
|
34
34
|
task_id: str
|
|
35
|
-
task_status: str
|
|
36
35
|
task_phase: str
|
|
37
36
|
task_phase_stage: int
|
|
37
|
+
task_status: str
|
|
38
38
|
|
|
39
39
|
input_data_id: str
|
|
40
40
|
input_data_name: str
|
|
@@ -162,9 +162,9 @@ def create_df(
|
|
|
162
162
|
base_columns = [
|
|
163
163
|
"project_id",
|
|
164
164
|
"task_id",
|
|
165
|
-
"task_status",
|
|
166
165
|
"task_phase",
|
|
167
166
|
"task_phase_stage",
|
|
167
|
+
"task_status",
|
|
168
168
|
"input_data_id",
|
|
169
169
|
"input_data_name",
|
|
170
170
|
"updated_datetime",
|
|
@@ -32,9 +32,9 @@ logger = logging.getLogger(__name__)
|
|
|
32
32
|
class AnnotationBoundingBoxInfo(DataClassJsonMixin):
|
|
33
33
|
project_id: str
|
|
34
34
|
task_id: str
|
|
35
|
-
task_status: str
|
|
36
35
|
task_phase: str
|
|
37
36
|
task_phase_stage: int
|
|
37
|
+
task_status: str
|
|
38
38
|
|
|
39
39
|
input_data_id: str
|
|
40
40
|
input_data_name: str
|
|
@@ -128,9 +128,9 @@ def create_df(
|
|
|
128
128
|
base_columns = [
|
|
129
129
|
"project_id",
|
|
130
130
|
"task_id",
|
|
131
|
-
"task_status",
|
|
132
131
|
"task_phase",
|
|
133
132
|
"task_phase_stage",
|
|
133
|
+
"task_status",
|
|
134
134
|
"input_data_id",
|
|
135
135
|
"input_data_name",
|
|
136
136
|
"updated_datetime",
|
|
@@ -36,9 +36,9 @@ class AnnotationPolygonInfo(BaseModel):
|
|
|
36
36
|
|
|
37
37
|
project_id: str
|
|
38
38
|
task_id: str
|
|
39
|
-
task_status: str
|
|
40
39
|
task_phase: str
|
|
41
40
|
task_phase_stage: int
|
|
41
|
+
task_status: str
|
|
42
42
|
|
|
43
43
|
input_data_id: str
|
|
44
44
|
input_data_name: str
|
|
@@ -183,9 +183,9 @@ def create_df(
|
|
|
183
183
|
base_columns = [
|
|
184
184
|
"project_id",
|
|
185
185
|
"task_id",
|
|
186
|
-
"task_status",
|
|
187
186
|
"task_phase",
|
|
188
187
|
"task_phase_stage",
|
|
188
|
+
"task_status",
|
|
189
189
|
"input_data_id",
|
|
190
190
|
"input_data_name",
|
|
191
191
|
"updated_datetime",
|
|
@@ -35,9 +35,9 @@ class AnnotationPolylineInfo(BaseModel):
|
|
|
35
35
|
|
|
36
36
|
project_id: str
|
|
37
37
|
task_id: str
|
|
38
|
-
task_status: str
|
|
39
38
|
task_phase: str
|
|
40
39
|
task_phase_stage: int
|
|
40
|
+
task_status: str
|
|
41
41
|
|
|
42
42
|
input_data_id: str
|
|
43
43
|
input_data_name: str
|
|
@@ -191,9 +191,9 @@ def create_df(
|
|
|
191
191
|
base_columns = [
|
|
192
192
|
"project_id",
|
|
193
193
|
"task_id",
|
|
194
|
-
"task_status",
|
|
195
194
|
"task_phase",
|
|
196
195
|
"task_phase_stage",
|
|
196
|
+
"task_status",
|
|
197
197
|
"input_data_id",
|
|
198
198
|
"input_data_name",
|
|
199
199
|
"updated_datetime",
|
|
@@ -32,9 +32,9 @@ logger = logging.getLogger(__name__)
|
|
|
32
32
|
class RangeAnnotationInfo(DataClassJsonMixin):
|
|
33
33
|
project_id: str
|
|
34
34
|
task_id: str
|
|
35
|
-
task_status: str
|
|
36
35
|
task_phase: str
|
|
37
36
|
task_phase_stage: int
|
|
37
|
+
task_status: str
|
|
38
38
|
|
|
39
39
|
input_data_id: str
|
|
40
40
|
input_data_name: str
|
|
@@ -118,9 +118,9 @@ def create_df(
|
|
|
118
118
|
base_columns = [
|
|
119
119
|
"project_id",
|
|
120
120
|
"task_id",
|
|
121
|
-
"task_status",
|
|
122
121
|
"task_phase",
|
|
123
122
|
"task_phase_stage",
|
|
123
|
+
"task_status",
|
|
124
124
|
"input_data_id",
|
|
125
125
|
"input_data_name",
|
|
126
126
|
"updated_datetime",
|
|
@@ -30,9 +30,9 @@ logger = logging.getLogger(__name__)
|
|
|
30
30
|
class AnnotationSinglePointInfo(DataClassJsonMixin):
|
|
31
31
|
project_id: str
|
|
32
32
|
task_id: str
|
|
33
|
-
task_status: str
|
|
34
33
|
task_phase: str
|
|
35
34
|
task_phase_stage: int
|
|
35
|
+
task_status: str
|
|
36
36
|
|
|
37
37
|
input_data_id: str
|
|
38
38
|
input_data_name: str
|
|
@@ -108,9 +108,9 @@ def create_df(
|
|
|
108
108
|
base_columns = [
|
|
109
109
|
"project_id",
|
|
110
110
|
"task_id",
|
|
111
|
-
"task_status",
|
|
112
111
|
"task_phase",
|
|
113
112
|
"task_phase_stage",
|
|
113
|
+
"task_status",
|
|
114
114
|
"input_data_id",
|
|
115
115
|
"input_data_name",
|
|
116
116
|
"updated_datetime",
|
|
@@ -95,8 +95,8 @@ class DeleteCommentMain(CommandLineWithConfirm):
|
|
|
95
95
|
task: dict[str, Any],
|
|
96
96
|
) -> bool:
|
|
97
97
|
task_id = task["task_id"]
|
|
98
|
-
if task["status"] not in [TaskStatus.NOT_STARTED.value, TaskStatus.
|
|
99
|
-
logger.warning(f"task_id='{task_id}' :
|
|
98
|
+
if task["status"] not in [TaskStatus.NOT_STARTED.value, TaskStatus.BREAK.value]:
|
|
99
|
+
logger.warning(f"task_id='{task_id}' : タスクの状態が未着手,休憩中 以外の状態なので、コメントを削除できません。(task_status='{task['status']}')")
|
|
100
100
|
return False
|
|
101
101
|
return True
|
|
102
102
|
|
|
@@ -9,6 +9,7 @@ from typing import Any
|
|
|
9
9
|
import annofabapi
|
|
10
10
|
import requests
|
|
11
11
|
from annofabapi.models import CommentType, TaskPhase, TaskStatus
|
|
12
|
+
from annofabapi.pydantic_models.input_data_type import InputDataType
|
|
12
13
|
from dataclasses_json import DataClassJsonMixin
|
|
13
14
|
|
|
14
15
|
from annofabcli.comment.utils import get_comment_type_name
|
|
@@ -18,6 +19,18 @@ from annofabcli.common.type_util import assert_noreturn
|
|
|
18
19
|
|
|
19
20
|
logger = logging.getLogger(__name__)
|
|
20
21
|
|
|
22
|
+
SUPPORTED_ANNOTATION_TYPES_FOR_INSPECTION_DATA = frozenset(
|
|
23
|
+
[
|
|
24
|
+
"user_bounding_box",
|
|
25
|
+
"bounding_box",
|
|
26
|
+
"polygon",
|
|
27
|
+
"polyline",
|
|
28
|
+
"point",
|
|
29
|
+
"range",
|
|
30
|
+
]
|
|
31
|
+
)
|
|
32
|
+
"""検査コメントの座標情報(InspectionData形式)への変換をサポートしているアノテーションタイプ"""
|
|
33
|
+
|
|
21
34
|
|
|
22
35
|
@dataclass
|
|
23
36
|
class AddedComment(DataClassJsonMixin):
|
|
@@ -28,15 +41,18 @@ class AddedComment(DataClassJsonMixin):
|
|
|
28
41
|
comment: str
|
|
29
42
|
"""コメントの中身"""
|
|
30
43
|
|
|
31
|
-
data: dict[str, Any] | None
|
|
44
|
+
data: dict[str, Any] | None = None
|
|
32
45
|
"""コメントを付与する位置や区間"""
|
|
33
46
|
|
|
34
|
-
annotation_id: str | None
|
|
47
|
+
annotation_id: str | None = None
|
|
35
48
|
"""コメントに紐付けるアノテーションID"""
|
|
36
49
|
|
|
37
|
-
phrases: list[str] | None
|
|
50
|
+
phrases: list[str] | None = None
|
|
38
51
|
"""参照している定型指摘ID"""
|
|
39
52
|
|
|
53
|
+
comment_id: str | None = None
|
|
54
|
+
"""コメントID。省略時はUUIDv4が自動生成される。"""
|
|
55
|
+
|
|
40
56
|
|
|
41
57
|
AddedCommentsForTask = dict[str, list[AddedComment]]
|
|
42
58
|
"""
|
|
@@ -51,6 +67,71 @@ keyはtask_id
|
|
|
51
67
|
"""
|
|
52
68
|
|
|
53
69
|
|
|
70
|
+
def convert_annotation_body_to_inspection_data( # noqa: PLR0911
|
|
71
|
+
annotation_body: dict[str, Any],
|
|
72
|
+
annotation_type: str,
|
|
73
|
+
input_data_type: InputDataType,
|
|
74
|
+
) -> dict[str, Any]:
|
|
75
|
+
"""
|
|
76
|
+
アノテーションのbody部分を、検査コメントの座標情報(`InspectionData`形式)に変換する。
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
annotation_body: Annotationの座標情報。AnnotationDetailContentOutputのdict形式
|
|
80
|
+
annotation_type: アノテーションタイプ。`SUPPORTED_ANNOTATION_TYPES_FOR_INSPECTION_DATA`のいずれかを指定すること。
|
|
81
|
+
input_data_type: プロジェクトの入力データタイプ。
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
検査コメントの座標情報(`InspectionData`形式)
|
|
85
|
+
"""
|
|
86
|
+
match input_data_type:
|
|
87
|
+
case InputDataType.MOVIE:
|
|
88
|
+
match annotation_type:
|
|
89
|
+
case "range":
|
|
90
|
+
# 区間の開始位置をTime形式に変換
|
|
91
|
+
return {"start": annotation_body["data"]["begin"], "end": annotation_body["data"]["end"], "_type": "Time"}
|
|
92
|
+
case _:
|
|
93
|
+
# "Classification"など、Time形式以外のアノテーションタイプ
|
|
94
|
+
return {"start": 0, "end": 100, "_type": "Time"}
|
|
95
|
+
|
|
96
|
+
case InputDataType.CUSTOM:
|
|
97
|
+
match annotation_type:
|
|
98
|
+
case "user_bounding_box":
|
|
99
|
+
# 3次元バウンディングボックスの場合、data.dataの文字列をパースして返す
|
|
100
|
+
return {"data": annotation_body["data"]["data"], "_type": "Custom"}
|
|
101
|
+
case _:
|
|
102
|
+
# セグメントなど
|
|
103
|
+
return {
|
|
104
|
+
"data": '{"kind": "CUBOID", "shape": {"dimensions": {"width": 1.0, "height": 1.0, "depth": 1.0}, "location": {"x": 0.0, "y": 0.0, "z": 0.0}, "rotation": {"x": 0.0, "y": 0.0, "z": 0.0}, "direction": {"front": {"x": 1.0, "y": 0.0, "z": 0.0}, "up": {"x": 0.0, "y": 0.0, "z": 1.0}}}, "version": "2"}', # noqa: E501
|
|
105
|
+
"_type": "Custom",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
case InputDataType.IMAGE:
|
|
109
|
+
match annotation_type:
|
|
110
|
+
case "bounding_box":
|
|
111
|
+
# 中心点を計算
|
|
112
|
+
left_top = annotation_body["data"]["left_top"]
|
|
113
|
+
right_bottom = annotation_body["data"]["right_bottom"]
|
|
114
|
+
center_x = (left_top["x"] + right_bottom["x"]) / 2
|
|
115
|
+
center_y = (left_top["y"] + right_bottom["y"]) / 2
|
|
116
|
+
return {"x": center_x, "y": center_y, "_type": "Point"}
|
|
117
|
+
case "polygon" | "polyline":
|
|
118
|
+
# 先頭の点を取得
|
|
119
|
+
points = annotation_body["data"]["points"]
|
|
120
|
+
assert len(points) > 0
|
|
121
|
+
first_point = points[0]
|
|
122
|
+
return {"x": first_point["x"], "y": first_point["y"], "_type": "Point"}
|
|
123
|
+
case "point":
|
|
124
|
+
# 点の形式に変換(pointキーから取り出す)
|
|
125
|
+
point = annotation_body["data"]["point"]
|
|
126
|
+
return {"x": point["x"], "y": point["y"], "_type": "Point"}
|
|
127
|
+
case "range":
|
|
128
|
+
# 区間の開始位置をTime形式に変換
|
|
129
|
+
return {"start": annotation_body["data"]["begin"], "end": annotation_body["data"]["end"], "_type": "Time"}
|
|
130
|
+
case _:
|
|
131
|
+
# 塗りつぶしや分類など
|
|
132
|
+
return {"x": 0, "y": 0, "_type": "Point"}
|
|
133
|
+
|
|
134
|
+
|
|
54
135
|
class PutCommentMain(CommandLineWithConfirm):
|
|
55
136
|
def __init__(self, service: annofabapi.Resource, project_id: str, comment_type: CommentType, all_yes: bool = False) -> None: # noqa: FBT001, FBT002
|
|
56
137
|
self.service = service
|
|
@@ -60,30 +141,68 @@ class PutCommentMain(CommandLineWithConfirm):
|
|
|
60
141
|
self.comment_type = comment_type
|
|
61
142
|
self.comment_type_name = get_comment_type_name(comment_type)
|
|
62
143
|
|
|
144
|
+
# プロジェクト情報を取得
|
|
145
|
+
project, _ = self.service.api.get_project(self.project_id)
|
|
146
|
+
self.input_data_type = InputDataType(project["input_data_type"])
|
|
147
|
+
|
|
148
|
+
# アノテーション仕様を取得
|
|
149
|
+
annotation_specs, _ = self.service.api.get_annotation_specs(self.project_id, query_params={"v": "3"})
|
|
150
|
+
self.dict_label_id_annotation_type = {label["label_id"]: label["annotation_type"] for label in annotation_specs["labels"]}
|
|
151
|
+
|
|
63
152
|
CommandLineWithConfirm.__init__(self, all_yes)
|
|
64
153
|
|
|
65
154
|
def _create_request_body(self, task: dict[str, Any], input_data_id: str, comments: list[AddedComment]) -> list[dict[str, Any]]:
|
|
66
155
|
"""batch_update_comments に渡すリクエストボディを作成する。"""
|
|
156
|
+
task_id = task["task_id"]
|
|
157
|
+
|
|
158
|
+
# annotation_idが指定されているがdataがNoneのコメントがあるか確認
|
|
159
|
+
need_annotation_data = any(c.annotation_id is not None and c.data is None for c in comments)
|
|
160
|
+
|
|
161
|
+
dict_annotation_id_label_id: dict[str, str] = {}
|
|
162
|
+
dict_annotation_id_data: dict[str, dict[str, Any]] = {}
|
|
67
163
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
164
|
+
if need_annotation_data:
|
|
165
|
+
# アノテーション詳細を取得
|
|
166
|
+
editor_annotation, _ = self.service.api.get_editor_annotation(self.project_id, task_id, input_data_id, query_params={"v": "2"})
|
|
167
|
+
details = editor_annotation["details"]
|
|
72
168
|
|
|
73
|
-
|
|
169
|
+
for detail in details:
|
|
170
|
+
annotation_id = detail["annotation_id"]
|
|
171
|
+
label_id = detail["label_id"]
|
|
172
|
+
dict_annotation_id_label_id[annotation_id] = label_id
|
|
173
|
+
|
|
174
|
+
# annotation_typeを取得
|
|
175
|
+
if label_id in self.dict_label_id_annotation_type:
|
|
176
|
+
# アノテーション仕様に存在しないラベルを使っているアノテーション(アノテーションを作成してから仕様を変更した場合)もあるので、判定する
|
|
177
|
+
annotation_type = self.dict_label_id_annotation_type[label_id]
|
|
178
|
+
dict_annotation_id_data[annotation_id] = convert_annotation_body_to_inspection_data(detail["body"], annotation_type, input_data_type=self.input_data_type)
|
|
179
|
+
else:
|
|
180
|
+
# annotation_idからlabel_idを取得するためだけにAPIを呼ぶ
|
|
181
|
+
editor_annotation, _ = self.service.api.get_editor_annotation(self.project_id, task_id, input_data_id, query_params={"v": "2"})
|
|
182
|
+
details = editor_annotation["details"]
|
|
183
|
+
dict_annotation_id_label_id = {e["annotation_id"]: e["label_id"] for e in details}
|
|
74
184
|
|
|
75
|
-
def _convert(comment: AddedComment) -> dict[str, Any]:
|
|
185
|
+
def _convert(comment: AddedComment) -> dict[str, Any] | None:
|
|
186
|
+
data = comment.data
|
|
187
|
+
annotation_id = comment.annotation_id
|
|
188
|
+
|
|
189
|
+
# dataがNoneでannotation_idが指定されている場合、dataを補完
|
|
190
|
+
if data is None:
|
|
191
|
+
assert annotation_id is not None
|
|
192
|
+
data = dict_annotation_id_data[annotation_id]
|
|
193
|
+
|
|
194
|
+
assert data is not None
|
|
76
195
|
return {
|
|
77
|
-
"comment_id": str(uuid.uuid4()),
|
|
196
|
+
"comment_id": comment.comment_id if comment.comment_id is not None else str(uuid.uuid4()),
|
|
78
197
|
"phase": task["phase"],
|
|
79
198
|
"phase_stage": task["phase_stage"],
|
|
80
199
|
"account_id": self.service.api.account_id,
|
|
81
200
|
"comment_type": self.comment_type.value,
|
|
82
201
|
"comment": comment.comment,
|
|
83
202
|
"comment_node": {
|
|
84
|
-
"data":
|
|
85
|
-
"annotation_id":
|
|
86
|
-
"label_id": dict_annotation_id_label_id.get(
|
|
203
|
+
"data": data,
|
|
204
|
+
"annotation_id": annotation_id,
|
|
205
|
+
"label_id": dict_annotation_id_label_id.get(annotation_id) if annotation_id is not None else None,
|
|
87
206
|
"status": "open",
|
|
88
207
|
"_type": "Root",
|
|
89
208
|
},
|
|
@@ -91,7 +210,8 @@ class PutCommentMain(CommandLineWithConfirm):
|
|
|
91
210
|
"_type": "Put",
|
|
92
211
|
}
|
|
93
212
|
|
|
94
|
-
|
|
213
|
+
converted_comments = [_convert(e) for e in comments]
|
|
214
|
+
return [c for c in converted_comments if c is not None]
|
|
95
215
|
|
|
96
216
|
def change_to_working_status(self, project_id: str, task: dict[str, Any]) -> dict[str, Any]:
|
|
97
217
|
"""
|
|
@@ -129,8 +249,8 @@ class PutCommentMain(CommandLineWithConfirm):
|
|
|
129
249
|
logger.warning(f"task_id='{task_id}' :: フェーズが検査/受入でないため検査コメントを付与できません。 :: task_phase='{task['phase']}'")
|
|
130
250
|
return False
|
|
131
251
|
|
|
132
|
-
if task["status"] not in [TaskStatus.NOT_STARTED.value, TaskStatus.
|
|
133
|
-
logger.warning(f"task_id='{task_id}' ::
|
|
252
|
+
if task["status"] not in [TaskStatus.NOT_STARTED.value, TaskStatus.BREAK.value]:
|
|
253
|
+
logger.warning(f"task_id='{task_id}' :: タスクの状態が未着手,休憩中 以外の状態なので、コメントを付与できません。 :: task_status='{task['status']}'")
|
|
134
254
|
return False
|
|
135
255
|
return True
|
|
136
256
|
|
|
@@ -248,7 +368,7 @@ def convert_cli_comments(dict_comments: dict[str, Any], *, comment_type: Comment
|
|
|
248
368
|
comment: str
|
|
249
369
|
"""コメントの中身"""
|
|
250
370
|
|
|
251
|
-
data: dict[str, Any]
|
|
371
|
+
data: dict[str, Any] | None = None
|
|
252
372
|
"""コメントを付与する位置や区間"""
|
|
253
373
|
|
|
254
374
|
annotation_id: str | None = None
|
|
@@ -257,6 +377,9 @@ def convert_cli_comments(dict_comments: dict[str, Any], *, comment_type: Comment
|
|
|
257
377
|
phrases: list[str] | None = None
|
|
258
378
|
"""参照している定型指摘ID"""
|
|
259
379
|
|
|
380
|
+
comment_id: str | None = None
|
|
381
|
+
"""コメントID。省略時はUUIDv4が自動生成される。"""
|
|
382
|
+
|
|
260
383
|
@dataclass
|
|
261
384
|
class AddedOnholdComment(DataClassJsonMixin):
|
|
262
385
|
"""
|
|
@@ -269,13 +392,16 @@ def convert_cli_comments(dict_comments: dict[str, Any], *, comment_type: Comment
|
|
|
269
392
|
annotation_id: str | None = None
|
|
270
393
|
"""コメントに紐付けるアノテーションID"""
|
|
271
394
|
|
|
395
|
+
comment_id: str | None = None
|
|
396
|
+
"""コメントID。省略時はUUIDv4が自動生成される。"""
|
|
397
|
+
|
|
272
398
|
def convert_inspection_comment(comment: dict[str, Any]) -> AddedComment:
|
|
273
399
|
tmp = AddedInspectionComment.from_dict(comment)
|
|
274
|
-
return AddedComment(comment=tmp.comment, data=tmp.data, annotation_id=tmp.annotation_id, phrases=tmp.phrases)
|
|
400
|
+
return AddedComment(comment=tmp.comment, data=tmp.data, annotation_id=tmp.annotation_id, phrases=tmp.phrases, comment_id=tmp.comment_id)
|
|
275
401
|
|
|
276
402
|
def convert_onhold_comment(comment: dict[str, Any]) -> AddedComment:
|
|
277
403
|
tmp = AddedOnholdComment.from_dict(comment)
|
|
278
|
-
return AddedComment(comment=tmp.comment, annotation_id=tmp.annotation_id, data=None, phrases=None)
|
|
404
|
+
return AddedComment(comment=tmp.comment, annotation_id=tmp.annotation_id, data=None, phrases=None, comment_id=tmp.comment_id)
|
|
279
405
|
|
|
280
406
|
if comment_type == CommentType.INSPECTION:
|
|
281
407
|
func_convert = convert_inspection_comment
|
|
@@ -31,6 +31,9 @@ class AddedSimpleComment:
|
|
|
31
31
|
phrases: list[str] | None = None
|
|
32
32
|
"""参照している定型指摘ID"""
|
|
33
33
|
|
|
34
|
+
comment_id: str | None = None
|
|
35
|
+
"""コメントID。省略時はUUIDv4が自動生成される。"""
|
|
36
|
+
|
|
34
37
|
|
|
35
38
|
class PutCommentSimplyMain(CommandLineWithConfirm):
|
|
36
39
|
def __init__(self, service: annofabapi.Resource, project_id: str, comment_type: CommentType, all_yes: bool = False) -> None: # noqa: FBT001, FBT002
|
|
@@ -49,7 +52,7 @@ class PutCommentSimplyMain(CommandLineWithConfirm):
|
|
|
49
52
|
def _convert(comment: AddedSimpleComment) -> dict[str, Any]:
|
|
50
53
|
return {
|
|
51
54
|
"comment": comment.comment,
|
|
52
|
-
"comment_id": str(uuid.uuid4()),
|
|
55
|
+
"comment_id": comment.comment_id if comment.comment_id is not None else str(uuid.uuid4()),
|
|
53
56
|
"phase": task["phase"],
|
|
54
57
|
"phase_stage": task["phase_stage"],
|
|
55
58
|
"comment_type": self.comment_type.value,
|
|
@@ -90,11 +93,11 @@ class PutCommentSimplyMain(CommandLineWithConfirm):
|
|
|
90
93
|
|
|
91
94
|
if self.comment_type == CommentType.INSPECTION: # noqa: SIM102
|
|
92
95
|
if task["phase"] == TaskPhase.ANNOTATION.value:
|
|
93
|
-
logger.warning(f"task_id='{task_id}'
|
|
96
|
+
logger.warning(f"task_id='{task_id}' :: フェーズが検査/受入でないため検査コメントを付与できません。 :: task_phase='{task['phase']}'")
|
|
94
97
|
return False
|
|
95
98
|
|
|
96
|
-
if task["status"] not in [TaskStatus.NOT_STARTED.value, TaskStatus.
|
|
97
|
-
logger.warning(f"task_id='{task_id}'
|
|
99
|
+
if task["status"] not in [TaskStatus.NOT_STARTED.value, TaskStatus.BREAK.value]:
|
|
100
|
+
logger.warning(f"task_id='{task_id}' :: タスクの状態が未着手,休憩中 以外の状態なので、コメントを付与できません。 :: task_status='{task['status']}'")
|
|
98
101
|
return False
|
|
99
102
|
return True
|
|
100
103
|
|
|
@@ -68,7 +68,11 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
68
68
|
parser.add_argument(
|
|
69
69
|
"--json",
|
|
70
70
|
type=str,
|
|
71
|
-
help=(
|
|
71
|
+
help=(
|
|
72
|
+
f"付与する検査コメントの内容をJSON形式で指定してください。``file://`` を先頭に付けると、JSON形式のファイルを指定できます。\n\n"
|
|
73
|
+
f"各コメントには ``comment_id`` を指定することができます。省略した場合は自動的にUUIDv4が生成されます。\n\n"
|
|
74
|
+
f"(ex) ``{json.dumps(SAMPLE_JSON, ensure_ascii=False)}``"
|
|
75
|
+
),
|
|
72
76
|
)
|
|
73
77
|
|
|
74
78
|
parser.add_argument(
|
|
@@ -69,7 +69,11 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
69
69
|
parser.add_argument(
|
|
70
70
|
"--json",
|
|
71
71
|
type=str,
|
|
72
|
-
help=(
|
|
72
|
+
help=(
|
|
73
|
+
f"付与する保留コメントの情報をJSON形式で指定してください。``file://`` を先頭に付けると、JSON形式のファイルを指定できます。\n\n"
|
|
74
|
+
f"各コメントには ``comment_id`` を指定することができます。省略した場合は自動的にUUIDv4が生成されます。\n\n"
|
|
75
|
+
f"(ex) ``{json.dumps(SAMPLE_JSON, ensure_ascii=False)}``"
|
|
76
|
+
),
|
|
73
77
|
)
|
|
74
78
|
|
|
75
79
|
parser.add_argument(
|
|
@@ -38,9 +38,9 @@ def _create_dict_tasks_by_input_data_id(task_list: list[dict[str, Any]]) -> dict
|
|
|
38
38
|
for input_data_index, input_data_id in enumerate(task["input_data_id_list"]):
|
|
39
39
|
new_task = {
|
|
40
40
|
"task_id": task["task_id"],
|
|
41
|
-
"task_status": task["status"],
|
|
42
41
|
"task_phase": task["phase"],
|
|
43
42
|
"task_phase_stage": task["phase_stage"],
|
|
43
|
+
"task_status": task["status"],
|
|
44
44
|
"frame_no": input_data_index + 1,
|
|
45
45
|
}
|
|
46
46
|
result[input_data_id].append(new_task)
|
|
@@ -70,7 +70,7 @@ def create_df_input_data_with_merged_task(input_data_list: list[dict[str, Any]])
|
|
|
70
70
|
"""
|
|
71
71
|
|
|
72
72
|
def get_columns(columns: pandas.Index) -> list[str]:
|
|
73
|
-
task_columns = ["task_id", "
|
|
73
|
+
task_columns = ["task_id", "task_phase", "task_phase_stage", "task_status", "frame_no"]
|
|
74
74
|
new_columns = columns.drop(task_columns)
|
|
75
75
|
return list(new_columns) + task_columns
|
|
76
76
|
|
|
@@ -93,7 +93,7 @@ def create_df_input_data_with_merged_task(input_data_list: list[dict[str, Any]])
|
|
|
93
93
|
# ネストしたオブジェクトを`system_metadata.input_duration`のような列名でアクセスできるようにするため
|
|
94
94
|
df_input_data = pandas.json_normalize(new_input_data_list)
|
|
95
95
|
|
|
96
|
-
for column in ["task_id", "
|
|
96
|
+
for column in ["task_id", "task_phase", "task_phase_stage", "task_status", "frame_no"]:
|
|
97
97
|
if column not in df_input_data.columns:
|
|
98
98
|
df_input_data[column] = pandas.NA
|
|
99
99
|
|
|
@@ -573,9 +573,9 @@ class AttributeCountCsv:
|
|
|
573
573
|
basic_columns = [
|
|
574
574
|
("project_id", "", ""),
|
|
575
575
|
("task_id", "", ""),
|
|
576
|
-
("task_status", "", ""),
|
|
577
576
|
("task_phase", "", ""),
|
|
578
577
|
("task_phase_stage", "", ""),
|
|
578
|
+
("task_status", "", ""),
|
|
579
579
|
("input_data_count", "", ""),
|
|
580
580
|
("annotation_count", "", ""),
|
|
581
581
|
]
|
|
@@ -622,9 +622,9 @@ class AttributeCountCsv:
|
|
|
622
622
|
basic_columns = [
|
|
623
623
|
("project_id", "", ""),
|
|
624
624
|
("task_id", "", ""),
|
|
625
|
-
("task_status", "", ""),
|
|
626
625
|
("task_phase", "", ""),
|
|
627
626
|
("task_phase_stage", "", ""),
|
|
627
|
+
("task_status", "", ""),
|
|
628
628
|
("input_data_id", "", ""),
|
|
629
629
|
("input_data_name", "", ""),
|
|
630
630
|
("frame_no", "", ""),
|
|
@@ -708,9 +708,9 @@ class LabelCountCsv:
|
|
|
708
708
|
basic_columns = [
|
|
709
709
|
"project_id",
|
|
710
710
|
"task_id",
|
|
711
|
-
"task_status",
|
|
712
711
|
"task_phase",
|
|
713
712
|
"task_phase_stage",
|
|
713
|
+
"task_status",
|
|
714
714
|
"input_data_count",
|
|
715
715
|
"annotation_count",
|
|
716
716
|
]
|
|
@@ -757,9 +757,9 @@ class LabelCountCsv:
|
|
|
757
757
|
basic_columns = [
|
|
758
758
|
"project_id",
|
|
759
759
|
"task_id",
|
|
760
|
-
"task_status",
|
|
761
760
|
"task_phase",
|
|
762
761
|
"task_phase_stage",
|
|
762
|
+
"task_status",
|
|
763
763
|
"input_data_id",
|
|
764
764
|
"input_data_name",
|
|
765
765
|
"frame_no",
|
|
@@ -109,9 +109,9 @@ class AnnotationDuration(DataClassJsonMixin):
|
|
|
109
109
|
|
|
110
110
|
project_id: str
|
|
111
111
|
task_id: str
|
|
112
|
-
task_status: TaskStatus
|
|
113
112
|
task_phase: TaskPhase
|
|
114
113
|
task_phase_stage: int
|
|
114
|
+
task_status: TaskStatus
|
|
115
115
|
|
|
116
116
|
input_data_id: str
|
|
117
117
|
input_data_name: str
|
|
@@ -37,7 +37,7 @@ def get_video_duration_list(task_list: list[dict[str, Any]], input_data_list: li
|
|
|
37
37
|
result = []
|
|
38
38
|
for task in task_list:
|
|
39
39
|
task_id = task["task_id"]
|
|
40
|
-
elm = {"project_id": task["project_id"], "task_id": task_id, "
|
|
40
|
+
elm = {"project_id": task["project_id"], "task_id": task_id, "task_phase": task["phase"], "task_phase_stage": task["phase_stage"], "task_status": task["status"]}
|
|
41
41
|
input_data_id_list = task["input_data_id_list"]
|
|
42
42
|
assert len(input_data_id_list) == 1, f"task_id='{task_id}'には複数の入力データが含まれています。"
|
|
43
43
|
input_data_id = input_data_id_list[0]
|
|
@@ -35,24 +35,24 @@ annofabcli/annotation_specs/list_label_color.py,sha256=MrjTOfDpXvgMVDlfq0fLn46BH
|
|
|
35
35
|
annofabcli/annotation_specs/put_label_color.py,sha256=3op1Kck5TBn-ORIDmQOGgZGmfm_c4nmRuJy4g0vkEGQ,5956
|
|
36
36
|
annofabcli/annotation_specs/subcommand_annotation_specs.py,sha256=jOPgWLEmb721kxknmzlXLIFuvWwlaX17PJATfQDH5lo,2643
|
|
37
37
|
annofabcli/annotation_zip/__init__.py,sha256=wAeKgkUYvgzdGFS3iJ3h0WogWbg9i-0c4xSg-mzbBpY,64
|
|
38
|
-
annofabcli/annotation_zip/list_annotation_3d_bounding_box.py,sha256=
|
|
39
|
-
annofabcli/annotation_zip/list_annotation_bounding_box_2d.py,sha256=
|
|
40
|
-
annofabcli/annotation_zip/list_polygon_annotation.py,sha256=
|
|
41
|
-
annofabcli/annotation_zip/list_polyline_annotation.py,sha256=
|
|
42
|
-
annofabcli/annotation_zip/list_range_annotation.py,sha256=
|
|
43
|
-
annofabcli/annotation_zip/list_single_point_annotation.py,sha256=
|
|
38
|
+
annofabcli/annotation_zip/list_annotation_3d_bounding_box.py,sha256=pREb2YZ3glcWZi9_65O6SOmK_Hi5UncHVQGhe_3zsco,14716
|
|
39
|
+
annofabcli/annotation_zip/list_annotation_bounding_box_2d.py,sha256=Ue7ctGzlRE-tk5C-sULFLoQ5jtZ7p7LrxX6wEcp5zqE,13413
|
|
40
|
+
annofabcli/annotation_zip/list_polygon_annotation.py,sha256=0rYKoBbvEPOmtuJU_MfK-NNRbjmdhHJNlhmIFC44N2w,15558
|
|
41
|
+
annofabcli/annotation_zip/list_polyline_annotation.py,sha256=ahFx7hsoIovMZFUw7NyYs5fxodcfMsTRvsUECu9FzJ0,15813
|
|
42
|
+
annofabcli/annotation_zip/list_range_annotation.py,sha256=BagWABuV9IKbu41opis53JbTX1D5M07sjk9XK5hGga0,12665
|
|
43
|
+
annofabcli/annotation_zip/list_single_point_annotation.py,sha256=ylFhlUx2g-mqRuhwkaoAku8DrJh9afMTX443wSMWXJ8,12359
|
|
44
44
|
annofabcli/annotation_zip/subcommand_annotation_zip.py,sha256=RQb3FVMoXdbg1XK2-sa2vBaETv1bIWc4Lg8QHNCp3nA,2056
|
|
45
45
|
annofabcli/annotation_zip/validate_annotation.py,sha256=bgvzhiWo-M3gRYrJo3-buqBBx-Nt_jOOS5PQ4Iyj-OU,16636
|
|
46
46
|
annofabcli/comment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
-
annofabcli/comment/delete_comment.py,sha256=
|
|
47
|
+
annofabcli/comment/delete_comment.py,sha256=DT6s07IyCYXlSqEZop1CXloaORJVgcBvwR4BwswbQlQ,11288
|
|
48
48
|
annofabcli/comment/download_comment_json.py,sha256=wB8U31G-7pkvN05N2erZch91bqx6oumGr9ziIXIyLuY,2392
|
|
49
49
|
annofabcli/comment/list_all_comment.py,sha256=fFBBY6-9Tx51X7lVT6qblTfkQ7jWmZiqtNqkt-RB14c,8233
|
|
50
50
|
annofabcli/comment/list_comment.py,sha256=SMTGCALxnddDxy-xnqOjBc3ijfb9QIZ-G4ZMw2BwyxA,6137
|
|
51
|
-
annofabcli/comment/put_comment.py,sha256=
|
|
52
|
-
annofabcli/comment/put_comment_simply.py,sha256
|
|
53
|
-
annofabcli/comment/put_inspection_comment.py,sha256=
|
|
51
|
+
annofabcli/comment/put_comment.py,sha256=lpisYmcSYRqygdpZFB_XmXFWjk82EaCNXYhGfQE3MYA,18646
|
|
52
|
+
annofabcli/comment/put_comment_simply.py,sha256=2nWnv0ZzeemJ99h0c2mGqA1ydsfuim6CGJkY_Y-uPyg,8298
|
|
53
|
+
annofabcli/comment/put_inspection_comment.py,sha256=XJt1fS-lWIH54PNGKzU8FLYUITtpEk6HCn7Wp47esgk,3944
|
|
54
54
|
annofabcli/comment/put_inspection_comment_simply.py,sha256=sgDKoBXlAPcTaf4GpU4qtfB3VRADNn0cdr0Ritg54Bo,6749
|
|
55
|
-
annofabcli/comment/put_onhold_comment.py,sha256=
|
|
55
|
+
annofabcli/comment/put_onhold_comment.py,sha256=lm1KZ8NRteuw8BvRvmWRFdELs5QoWCpxLuygfte55qs,3604
|
|
56
56
|
annofabcli/comment/put_onhold_comment_simply.py,sha256=URZfo-SHA4mz4wAgSUbI8KBjEx3Jkc-nDz7tXZxqpK0,3216
|
|
57
57
|
annofabcli/comment/subcommand_comment.py,sha256=nI-18QOV7T6aSOPLThwdtmlogVgnakeVCliYRk5qUEY,1488
|
|
58
58
|
annofabcli/comment/utils.py,sha256=aUj7U6MtGh64F3Ko83y4NKPKyWAqcg-c1XLqjkmIpSk,350
|
|
@@ -90,7 +90,7 @@ annofabcli/input_data/delete_input_data.py,sha256=rG5wzudBxP2czHZpFAvdBZZUnj6m1L
|
|
|
90
90
|
annofabcli/input_data/delete_metadata_key_of_input_data.py,sha256=L-fb2pz94547AHovsxAjbrWU_83bCtpP_5xn_AhC7IE,8289
|
|
91
91
|
annofabcli/input_data/download_input_data_json.py,sha256=tiofL70qcYOjr0Ugl-VunbJJlXonFi5GReLQZ5VBxmo,2856
|
|
92
92
|
annofabcli/input_data/list_all_input_data.py,sha256=-_4jZr62va9CCgT0OtmJZcTOG403hJLsb4HgW3-dyRE,10717
|
|
93
|
-
annofabcli/input_data/list_all_input_data_merged_task.py,sha256=
|
|
93
|
+
annofabcli/input_data/list_all_input_data_merged_task.py,sha256=LRNKFj9NHKqN0TqNDg_cA7zIcjfldSazNSmBkwFBkHw,12631
|
|
94
94
|
annofabcli/input_data/list_input_data.py,sha256=--hO1ImV9ilKTW8vqENNP1TcWdzVQuFQqX-dG6ob2Ds,13189
|
|
95
95
|
annofabcli/input_data/put_input_data.py,sha256=XW_rLKyAzqRPVT5xhg2ea8zDK1vl0fAfOKjTjzRyHUM,18944
|
|
96
96
|
annofabcli/input_data/put_input_data_with_zip.py,sha256=sRdo_fEiLhv37YQ5CRL6fNynjv5ngHYmrje12q2wGpI,5543
|
|
@@ -154,9 +154,9 @@ annofabcli/statistics/linegraph.py,sha256=D2qMBykZAfGN8lf5EaOsbpEqH4mzl5E5ga9CI_
|
|
|
154
154
|
annofabcli/statistics/list_annotation_area.py,sha256=GiEwrE-DuOUavAVDSb0l5qcgGkn3gGn5SAtpa8Mwhak,13234
|
|
155
155
|
annofabcli/statistics/list_annotation_attribute.py,sha256=AH4OeqUhwCh19Kv93bFLZRV6o6oKwFklRdEw2FrOaVk,12669
|
|
156
156
|
annofabcli/statistics/list_annotation_attribute_filled_count.py,sha256=htzYE88hpE6ozWc0H6ALg8d9tJsxE2EtosHvjp4F49E,30294
|
|
157
|
-
annofabcli/statistics/list_annotation_count.py,sha256=
|
|
158
|
-
annofabcli/statistics/list_annotation_duration.py,sha256=
|
|
159
|
-
annofabcli/statistics/list_video_duration.py,sha256=
|
|
157
|
+
annofabcli/statistics/list_annotation_count.py,sha256=KsQ0_1GSEyF5pqGqzJzazCORe0F-lcylXXAEpSaKGyw,76230
|
|
158
|
+
annofabcli/statistics/list_annotation_duration.py,sha256=PeqeO6pTpp4mYApJX7JqDBeWwTjI_mwvxsoiCQbr_-Y,31870
|
|
159
|
+
annofabcli/statistics/list_video_duration.py,sha256=f2GGIgpsm-_f-U9Tnl68-VPatdqTBtebtQUnM9DuHw4,9142
|
|
160
160
|
annofabcli/statistics/list_worktime.py,sha256=vA7FNf6hqypMK868Q28HWoppD-exGK28HuUHARZIp-c,6451
|
|
161
161
|
annofabcli/statistics/scatter.py,sha256=bpEcB4bYUpIfjEEU7nhqhFDiesnjCGwqaThbU52sU8g,11008
|
|
162
162
|
annofabcli/statistics/subcommand_statistics.py,sha256=Uhw8OGHD4BeqyQijssI1PKZaA0gb-Stthn_i92qxqw8,2426
|
|
@@ -227,8 +227,8 @@ annofabcli/task_history_event/download_task_history_event_json.py,sha256=lWyOoS2
|
|
|
227
227
|
annofabcli/task_history_event/list_all_task_history_event.py,sha256=51p_c_sWflJ7Jsrkay-OgF6c8wCOHpnqQeGIHVKzi6E,8001
|
|
228
228
|
annofabcli/task_history_event/list_worktime.py,sha256=0X1irND_ElxC_XpHiPac6cjwIz9DhgAccfyDA3M7kh0,15481
|
|
229
229
|
annofabcli/task_history_event/subcommand_task_history_event.py,sha256=dFllzpm8plnnwADwTV74h-R2LOA7rZW-xd2YnSkwTHo,1229
|
|
230
|
-
annofabcli-1.114.
|
|
231
|
-
annofabcli-1.114.
|
|
232
|
-
annofabcli-1.114.
|
|
233
|
-
annofabcli-1.114.
|
|
234
|
-
annofabcli-1.114.
|
|
230
|
+
annofabcli-1.114.6.dist-info/METADATA,sha256=d6zPaNaifi8TGvORYdMhH0pp8Ku6Y5Q2pj2OVB6zJYg,4946
|
|
231
|
+
annofabcli-1.114.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
232
|
+
annofabcli-1.114.6.dist-info/entry_points.txt,sha256=C2uSUc-kkLJpoK_mDL5FEMAdorLEMPfwSf8VBMYnIFM,56
|
|
233
|
+
annofabcli-1.114.6.dist-info/licenses/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
|
|
234
|
+
annofabcli-1.114.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|