annofabcli 1.97.0__py3-none-any.whl → 1.99.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/__version__.py +1 -1
- annofabcli/annotation/merge_segmentation.py +390 -0
- annofabcli/annotation/remove_segmentation_overlap.py +343 -0
- annofabcli/annotation/subcommand_annotation.py +4 -0
- annofabcli/annotation_specs/put_label_color.py +5 -0
- annofabcli/comment/delete_comment.py +3 -0
- annofabcli/comment/put_inspection_comment.py +3 -0
- annofabcli/comment/put_onhold_comment.py +3 -0
- annofabcli/input_data/change_input_data_name.py +4 -1
- annofabcli/input_data/put_input_data.py +4 -0
- annofabcli/statistics/list_annotation_attribute_filled_count.py +684 -0
- annofabcli/statistics/list_annotation_count.py +80 -37
- annofabcli/statistics/list_annotation_duration.py +18 -18
- annofabcli/statistics/subcommand_statistics.py +3 -0
- annofabcli/statistics/visualization/dataframe/task.py +26 -7
- annofabcli/task/list_tasks_added_task_history.py +229 -161
- annofabcli/task/put_tasks.py +9 -4
- {annofabcli-1.97.0.dist-info → annofabcli-1.99.0.dist-info}/METADATA +2 -2
- {annofabcli-1.97.0.dist-info → annofabcli-1.99.0.dist-info}/RECORD +22 -19
- {annofabcli-1.97.0.dist-info → annofabcli-1.99.0.dist-info}/LICENSE +0 -0
- {annofabcli-1.97.0.dist-info → annofabcli-1.99.0.dist-info}/WHEEL +0 -0
- {annofabcli-1.97.0.dist-info → annofabcli-1.99.0.dist-info}/entry_points.txt +0 -0
|
@@ -9,175 +9,249 @@ import annofabapi
|
|
|
9
9
|
import more_itertools
|
|
10
10
|
import pandas
|
|
11
11
|
from annofabapi.models import Task, TaskHistory, TaskPhase, TaskStatus
|
|
12
|
+
from annofabapi.util.task_history import find_rejected_task_history_indices, get_task_creation_datetime
|
|
12
13
|
from annofabapi.utils import get_task_history_index_skipped_acceptance, get_task_history_index_skipped_inspection
|
|
13
14
|
|
|
14
15
|
import annofabcli
|
|
15
16
|
from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login
|
|
16
17
|
from annofabcli.common.enums import FormatArgument
|
|
17
18
|
from annofabcli.common.facade import AnnofabApiFacade
|
|
18
|
-
from annofabcli.common.utils import print_csv, print_json
|
|
19
|
+
from annofabcli.common.utils import isoduration_to_hour, print_csv, print_json
|
|
19
20
|
from annofabcli.common.visualize import AddProps
|
|
20
21
|
from annofabcli.task.list_tasks import ListTasksMain
|
|
21
22
|
|
|
22
23
|
logger = logging.getLogger(__name__)
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
"""
|
|
26
|
+
def get_post_rejection_annotation_worktime_hour(task_histories: list[TaskHistory]) -> float:
|
|
27
|
+
"""
|
|
28
|
+
検査/受入フェーズでの差し戻し後の教師付作業時間を算出します。
|
|
29
|
+
指摘による修正にかかった時間を把握するのに利用できます。
|
|
27
30
|
|
|
28
31
|
Args:
|
|
29
|
-
|
|
30
|
-
project_id: プロジェクトID
|
|
32
|
+
task_histories: タスク履歴
|
|
31
33
|
|
|
32
34
|
"""
|
|
35
|
+
rejected_task_history_indices = find_rejected_task_history_indices(task_histories)
|
|
36
|
+
if len(rejected_task_history_indices) == 0:
|
|
37
|
+
return 0.0
|
|
38
|
+
|
|
39
|
+
# 差し戻された履歴の直後で、教師付フェーズの作業時間を算出する
|
|
40
|
+
min_rejected_task_history_index = min(rejected_task_history_indices)
|
|
41
|
+
return sum(
|
|
42
|
+
isoduration_to_hour(history["accumulated_labor_time_milliseconds"])
|
|
43
|
+
for history in task_histories[min_rejected_task_history_index + 1 :]
|
|
44
|
+
if history["phase"] == TaskPhase.ANNOTATION.value
|
|
45
|
+
)
|
|
33
46
|
|
|
34
|
-
def __init__(self, service: annofabapi.Resource, project_id: str) -> None:
|
|
35
|
-
self.service = service
|
|
36
|
-
self.project_id = project_id
|
|
37
|
-
self.visualize = AddProps(self.service, project_id)
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
def get_post_rejection_inspection_worktime_hour(task_histories: list[TaskHistory]) -> float:
|
|
49
|
+
"""
|
|
50
|
+
検査/受入フェーズでの差し戻し後の検査作業時間を算出します。
|
|
42
51
|
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
Args:
|
|
53
|
+
task_histories: タスク履歴
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
"""
|
|
56
|
+
rejected_task_history_indices = find_rejected_task_history_indices(task_histories)
|
|
57
|
+
if len(rejected_task_history_indices) == 0:
|
|
58
|
+
return 0.0
|
|
59
|
+
|
|
60
|
+
# 差し戻された履歴の直後で、検査フェーズの作業時間を算出する
|
|
61
|
+
min_rejected_task_history_index = min(rejected_task_history_indices)
|
|
62
|
+
return sum(
|
|
63
|
+
isoduration_to_hour(history["accumulated_labor_time_milliseconds"])
|
|
64
|
+
for history in task_histories[min_rejected_task_history_index + 1 :]
|
|
65
|
+
if history["phase"] == TaskPhase.INSPECTION.value
|
|
66
|
+
)
|
|
58
67
|
|
|
59
|
-
@staticmethod
|
|
60
|
-
def get_task_created_datetime(task: dict[str, Any], task_histories: list[TaskHistory]) -> Optional[str]:
|
|
61
|
-
"""タスクの作成日時を取得する。
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
def get_post_rejection_acceptance_worktime_hour(task_histories: list[TaskHistory]) -> float:
|
|
70
|
+
"""
|
|
71
|
+
受入フェーズでの差し戻し後の受入作業時間を算出します。
|
|
65
72
|
|
|
66
|
-
Returns:
|
|
67
|
-
タスクの作成日時
|
|
68
|
-
"""
|
|
69
|
-
# 受入フェーズで完了日時がnot Noneの場合は、受入を合格したか差し戻したとき。
|
|
70
|
-
# したがって、後続のタスク履歴を見て、初めて受入完了状態になった日時を取得する。
|
|
71
|
-
if len(task_histories) == 0:
|
|
72
|
-
return None
|
|
73
|
-
|
|
74
|
-
first_history = task_histories[0]
|
|
75
|
-
# 2020年以前は、先頭のタスク履歴はタスク作成ではなく、教師付けの履歴である。2020年以前はタスク作成日時を取得できないのでNoneを返す。
|
|
76
|
-
# https://annofab.com/docs/releases/2020.html#v01020
|
|
77
|
-
if (
|
|
78
|
-
first_history["account_id"] is None
|
|
79
|
-
and first_history["accumulated_labor_time_milliseconds"] == "PT0S"
|
|
80
|
-
and first_history["phase"] == TaskPhase.ANNOTATION.value
|
|
81
|
-
):
|
|
82
|
-
if len(task_histories) == 1:
|
|
83
|
-
# 一度も作業されていないタスクは、先頭のタスク履歴のstarted_datetimeはNoneである
|
|
84
|
-
# 替わりにタスクの`operation_updated_datetime`をタスク作成日時とする
|
|
85
|
-
return task["operation_updated_datetime"]
|
|
86
|
-
return first_history["started_datetime"]
|
|
87
|
-
return None
|
|
88
73
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
"""はじめて受入完了状態になった日時を取得する。
|
|
74
|
+
Args:
|
|
75
|
+
task_histories: タスク履歴
|
|
92
76
|
|
|
93
|
-
|
|
94
|
-
|
|
77
|
+
"""
|
|
78
|
+
rejected_task_history_indices = find_rejected_task_history_indices(task_histories)
|
|
95
79
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
80
|
+
# 検査フェーズでの差し戻しは除外する
|
|
81
|
+
# 検査フェーズでの差し戻しは、受入作業の回数に影響しないため
|
|
82
|
+
acceptance_rejected_indices = [index for index in rejected_task_history_indices if task_histories[index]["phase"] == TaskPhase.ACCEPTANCE.value]
|
|
83
|
+
if len(acceptance_rejected_indices) == 0:
|
|
84
|
+
return 0.0
|
|
101
85
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
86
|
+
min_rejected_acceptance_task_history_index = min(acceptance_rejected_indices)
|
|
87
|
+
|
|
88
|
+
# 差し戻された履歴の直後以降で、受入フェーズの作業時間を算出する
|
|
89
|
+
return sum(
|
|
90
|
+
isoduration_to_hour(history["accumulated_labor_time_milliseconds"])
|
|
91
|
+
for history in task_histories[min_rejected_acceptance_task_history_index + 1 :]
|
|
92
|
+
if history["phase"] == TaskPhase.ACCEPTANCE.value
|
|
93
|
+
)
|
|
105
94
|
|
|
106
|
-
if index == len(task_histories) - 1:
|
|
107
|
-
# 末尾履歴なら、受入完了状態
|
|
108
|
-
return history["ended_datetime"]
|
|
109
95
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# 受入完了後、受入取り消し実行
|
|
113
|
-
return history["ended_datetime"]
|
|
114
|
-
# そうでなければ、受入フェーズでの差し戻し
|
|
96
|
+
def get_completed_datetime(task: dict[str, Any], task_histories: list[TaskHistory]) -> Optional[str]:
|
|
97
|
+
"""受入完了状態になった日時を取得する。
|
|
115
98
|
|
|
99
|
+
Args:
|
|
100
|
+
task_histories (List[TaskHistory]): [description]
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
str: 受入完了状態になった日時
|
|
104
|
+
"""
|
|
105
|
+
# 受入完了日時を設定
|
|
106
|
+
if task["phase"] == TaskPhase.ACCEPTANCE.value and task["status"] == TaskStatus.COMPLETE.value:
|
|
107
|
+
assert len(task_histories) > 0, (
|
|
108
|
+
f"task_id='{task['task_id']}'のタスク履歴が0件です。参照しているタスク履歴情報が古い可能性があります。 "
|
|
109
|
+
f":: phase='{task['phase']}', status='{task['status']}'"
|
|
110
|
+
)
|
|
111
|
+
return task_histories[-1]["ended_datetime"]
|
|
112
|
+
else:
|
|
116
113
|
return None
|
|
117
114
|
|
|
118
|
-
@staticmethod
|
|
119
|
-
def get_first_acceptance_reached_datetime(task_histories: list[TaskHistory]) -> Optional[str]:
|
|
120
|
-
"""はじめて受入フェーズに到達した日時を取得する。
|
|
121
|
-
受入フェーズを着手した日時とは異なる。
|
|
122
|
-
必ず`first_acceptance_started_datetime`よりも前の日時になる。
|
|
123
115
|
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
def get_first_acceptance_completed_datetime(task_histories: list[TaskHistory]) -> Optional[str]:
|
|
117
|
+
"""はじめて受入完了状態になった日時を取得する。
|
|
126
118
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if history["phase"] != TaskPhase.ACCEPTANCE.value:
|
|
130
|
-
continue
|
|
119
|
+
Args:
|
|
120
|
+
task_histories (List[TaskHistory]): [description]
|
|
131
121
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
122
|
+
Returns:
|
|
123
|
+
str: はじめて受入完了状態になった日時
|
|
124
|
+
"""
|
|
125
|
+
# 受入フェーズで完了日時がnot Noneの場合は、受入を合格したか差し戻したとき。
|
|
126
|
+
# したがって、後続のタスク履歴を見て、初めて受入完了状態になった日時を取得する。
|
|
136
127
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
128
|
+
for index, history in enumerate(task_histories):
|
|
129
|
+
if history["phase"] != TaskPhase.ACCEPTANCE.value or history["ended_datetime"] is None:
|
|
130
|
+
continue
|
|
140
131
|
|
|
141
|
-
|
|
142
|
-
|
|
132
|
+
if index == len(task_histories) - 1:
|
|
133
|
+
# 末尾履歴なら、受入完了状態
|
|
134
|
+
return history["ended_datetime"]
|
|
143
135
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return False
|
|
136
|
+
next_history = task_histories[index + 1]
|
|
137
|
+
if next_history["phase"] == TaskPhase.ACCEPTANCE.value:
|
|
138
|
+
# 受入完了後、受入取り消し実行
|
|
139
|
+
return history["ended_datetime"]
|
|
140
|
+
# そうでなければ、受入フェーズでの差し戻し
|
|
150
141
|
|
|
151
|
-
|
|
152
|
-
# ただし、スキップされた履歴より後で、「アノテーション一覧で修正された」受入フェーズがある場合(account_id is None)は、スキップされた受入とみなす。 # noqa: E501
|
|
153
|
-
last_task_history_index = task_history_index_list[-1]
|
|
154
|
-
return (
|
|
155
|
-
more_itertools.first_true(
|
|
156
|
-
task_histories[last_task_history_index + 1 :],
|
|
157
|
-
pred=lambda e: e["phase"] == TaskPhase.ACCEPTANCE.value and e["account_id"] is not None,
|
|
158
|
-
)
|
|
159
|
-
is None
|
|
160
|
-
)
|
|
142
|
+
return None
|
|
161
143
|
|
|
162
|
-
@staticmethod
|
|
163
|
-
def is_inspection_phase_skipped(task_histories: list[TaskHistory]) -> bool:
|
|
164
|
-
"""抜取検査によって、検査フェーズでスキップされたことがあるかを取得する。
|
|
165
144
|
|
|
166
|
-
|
|
167
|
-
|
|
145
|
+
def get_first_acceptance_reached_datetime(task_histories: list[TaskHistory]) -> Optional[str]:
|
|
146
|
+
"""
|
|
147
|
+
はじめて受入フェーズに到達した日時を取得する。
|
|
148
|
+
受入フェーズを着手した日時とは異なる。
|
|
149
|
+
必ず`first_acceptance_started_datetime`よりも前の日時になる。
|
|
168
150
|
|
|
169
|
-
|
|
170
|
-
bool: 検査フェーズでスキップされたことがあるかどうか
|
|
171
|
-
"""
|
|
172
|
-
task_history_index_list = get_task_history_index_skipped_inspection(task_histories)
|
|
173
|
-
if len(task_history_index_list) == 0:
|
|
174
|
-
return False
|
|
151
|
+
たとえば教師付フェーズで提出して受入フェーズに到達した場合、教師付フェーズを提出した日時が「受入フェーズに到達した日時」になる。
|
|
175
152
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
153
|
+
"""
|
|
154
|
+
for index, history in enumerate(task_histories):
|
|
155
|
+
if history["phase"] != TaskPhase.ACCEPTANCE.value:
|
|
156
|
+
continue
|
|
157
|
+
|
|
158
|
+
first_acceptance_reached_datetime = task_histories[index - 1]["ended_datetime"]
|
|
159
|
+
assert first_acceptance_reached_datetime is not None
|
|
160
|
+
return first_acceptance_reached_datetime
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def is_acceptance_phase_skipped(task_histories: list[TaskHistory]) -> bool:
|
|
165
|
+
"""抜取受入によって、受入フェーズでスキップされたことがあるかを取得する。
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
task_histories (List[TaskHistory]): タスク履歴
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
bool: 受入フェーズでスキップされたことがあるかどうか
|
|
172
|
+
"""
|
|
173
|
+
task_history_index_list = get_task_history_index_skipped_acceptance(task_histories)
|
|
174
|
+
if len(task_history_index_list) == 0:
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
# スキップされた履歴より後に受入フェーズがなければ、受入がスキップされたタスクとみなす
|
|
178
|
+
# ただし、スキップされた履歴より後で、「アノテーション一覧で修正された」受入フェーズがある場合(account_id is None)は、スキップされた受入とみなす。 # noqa: E501
|
|
179
|
+
last_task_history_index = task_history_index_list[-1]
|
|
180
|
+
return (
|
|
181
|
+
more_itertools.first_true(
|
|
182
|
+
task_histories[last_task_history_index + 1 :],
|
|
183
|
+
pred=lambda e: e["phase"] == TaskPhase.ACCEPTANCE.value and e["account_id"] is not None,
|
|
180
184
|
)
|
|
185
|
+
is None
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def calculate_total_worktime_in_phase(task_histories: list[TaskHistory], phase: TaskPhase) -> float:
|
|
190
|
+
"""指定したフェーズの合計作業時間を計算する。
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
task_histories: タスク履歴
|
|
194
|
+
phase: 計算対象のフェーズ
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
合計作業時間
|
|
198
|
+
"""
|
|
199
|
+
return sum(isoduration_to_hour(history["accumulated_labor_time_milliseconds"]) for history in task_histories if history["phase"] == phase.value)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def get_first_task_history(task_histories: list[TaskHistory], phase: TaskPhase) -> Optional[TaskHistory]:
|
|
203
|
+
"""
|
|
204
|
+
指定したフェーズの最初に作業したタスク履歴を取得します。
|
|
205
|
+
取得したタスク履歴には、account_idはnot Noneで、作業時間は0より大きいです。
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
task_histories: タスク履歴
|
|
209
|
+
phase: フェーズ
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
最初のタスク履歴
|
|
213
|
+
"""
|
|
214
|
+
for history in task_histories:
|
|
215
|
+
if (
|
|
216
|
+
history["phase"] == phase.value
|
|
217
|
+
and history["account_id"] is not None
|
|
218
|
+
and isoduration_to_hour(history["accumulated_labor_time_milliseconds"]) > 0
|
|
219
|
+
):
|
|
220
|
+
return history
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def is_inspection_phase_skipped(task_histories: list[TaskHistory]) -> bool:
|
|
225
|
+
"""抜取検査によって、検査フェーズでスキップされたことがあるかを取得する。
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
task_histories (List[TaskHistory]): タスク履歴
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
bool: 検査フェーズでスキップされたことがあるかどうか
|
|
232
|
+
"""
|
|
233
|
+
task_history_index_list = get_task_history_index_skipped_inspection(task_histories)
|
|
234
|
+
if len(task_history_index_list) == 0:
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
# スキップされた履歴より後に検査フェーズがなければ、検査がスキップされたタスクとみなす
|
|
238
|
+
last_task_history_index = task_history_index_list[-1]
|
|
239
|
+
return more_itertools.first_true(task_histories[last_task_history_index + 1 :], pred=lambda e: e["phase"] == TaskPhase.INSPECTION.value) is None
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class AddingAdditionalInfoToTask:
|
|
243
|
+
"""タスクに付加的な情報を追加するためのクラス
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
service: annofabapiにアクセスするためのインスタンス
|
|
247
|
+
project_id: プロジェクトID
|
|
248
|
+
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
def __init__(self, service: annofabapi.Resource, project_id: str) -> None:
|
|
252
|
+
self.service = service
|
|
253
|
+
self.project_id = project_id
|
|
254
|
+
self.visualize = AddProps(self.service, project_id)
|
|
181
255
|
|
|
182
256
|
def _add_task_history_info(self, task: Task, task_history: Optional[TaskHistory], column_prefix: str) -> Task:
|
|
183
257
|
"""
|
|
@@ -210,12 +284,12 @@ class AddingAdditionalInfoToTask:
|
|
|
210
284
|
}
|
|
211
285
|
)
|
|
212
286
|
|
|
213
|
-
|
|
214
|
-
if
|
|
287
|
+
member = self.visualize.get_project_member_from_account_id(account_id)
|
|
288
|
+
if member is not None:
|
|
215
289
|
task.update(
|
|
216
290
|
{
|
|
217
|
-
f"{column_prefix}_user_id":
|
|
218
|
-
f"{column_prefix}_username":
|
|
291
|
+
f"{column_prefix}_user_id": member["user_id"],
|
|
292
|
+
f"{column_prefix}_username": member["username"],
|
|
219
293
|
}
|
|
220
294
|
)
|
|
221
295
|
else:
|
|
@@ -223,27 +297,7 @@ class AddingAdditionalInfoToTask:
|
|
|
223
297
|
|
|
224
298
|
return task
|
|
225
299
|
|
|
226
|
-
def
|
|
227
|
-
task_history_by_phase = [
|
|
228
|
-
e
|
|
229
|
-
for e in task_histories
|
|
230
|
-
if e["phase"] == phase.value
|
|
231
|
-
and e["account_id"] is not None
|
|
232
|
-
and annofabcli.common.utils.isoduration_to_hour(e["accumulated_labor_time_milliseconds"]) > 0
|
|
233
|
-
]
|
|
234
|
-
|
|
235
|
-
# 最初の対象フェーズに関する情報を設定
|
|
236
|
-
first_task_history = task_history_by_phase[0] if len(task_history_by_phase) > 0 else None
|
|
237
|
-
self._add_task_history_info(task, first_task_history, column_prefix=f"first_{phase.value}")
|
|
238
|
-
|
|
239
|
-
# 作業時間に関する情報を設定
|
|
240
|
-
task[f"{phase.value}_worktime_hour"] = sum(
|
|
241
|
-
annofabcli.common.utils.isoduration_to_hour(e["accumulated_labor_time_milliseconds"]) for e in task_history_by_phase
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
return task
|
|
245
|
-
|
|
246
|
-
def add_additional_info_to_task(self, task: dict[str, Any]): # noqa: ANN201
|
|
300
|
+
def add_additional_info_to_task(self, task: dict[str, Any]) -> None:
|
|
247
301
|
"""タスクの付加的情報を、タスクに追加する。
|
|
248
302
|
以下の列を追加する。
|
|
249
303
|
* user_id
|
|
@@ -280,23 +334,29 @@ class AddingAdditionalInfoToTask:
|
|
|
280
334
|
|
|
281
335
|
"""
|
|
282
336
|
# タスク作成日時
|
|
283
|
-
task["created_datetime"] =
|
|
337
|
+
task["created_datetime"] = get_task_creation_datetime(task, task_histories)
|
|
284
338
|
|
|
285
339
|
# フェーズごとのタスク履歴情報を追加する
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
340
|
+
for phase in TaskPhase:
|
|
341
|
+
# タスク履歴から取得した作業時間を設定
|
|
342
|
+
task[f"{phase.value}_worktime_hour"] = calculate_total_worktime_in_phase(task_histories, phase)
|
|
343
|
+
first_task_history = get_first_task_history(task_histories, phase)
|
|
344
|
+
self._add_task_history_info(task, first_task_history, column_prefix=f"first_{phase.value}")
|
|
289
345
|
|
|
290
346
|
# 初めて受入が完了した日時
|
|
291
|
-
task["first_acceptance_reached_datetime"] =
|
|
292
|
-
task["first_acceptance_completed_datetime"] =
|
|
347
|
+
task["first_acceptance_reached_datetime"] = get_first_acceptance_reached_datetime(task_histories)
|
|
348
|
+
task["first_acceptance_completed_datetime"] = get_first_acceptance_completed_datetime(task_histories)
|
|
293
349
|
|
|
294
350
|
# 受入完了日時を設定
|
|
295
|
-
task["completed_datetime"] =
|
|
351
|
+
task["completed_datetime"] = get_completed_datetime(task, task_histories)
|
|
296
352
|
|
|
297
353
|
# 抜取検査/受入によって、スキップされたかどうか
|
|
298
|
-
task["inspection_is_skipped"] =
|
|
299
|
-
task["acceptance_is_skipped"] =
|
|
354
|
+
task["inspection_is_skipped"] = is_inspection_phase_skipped(task_histories)
|
|
355
|
+
task["acceptance_is_skipped"] = is_acceptance_phase_skipped(task_histories)
|
|
356
|
+
|
|
357
|
+
task["post_rejection_annotation_worktime_hour"] = get_post_rejection_annotation_worktime_hour(task_histories)
|
|
358
|
+
task["post_rejection_inspection_worktime_hour"] = get_post_rejection_inspection_worktime_hour(task_histories)
|
|
359
|
+
task["post_rejection_acceptance_worktime_hour"] = get_post_rejection_acceptance_worktime_hour(task_histories)
|
|
300
360
|
|
|
301
361
|
|
|
302
362
|
class ListTasksAddedTaskHistoryMain:
|
|
@@ -373,9 +433,17 @@ class TasksAddedTaskHistoryOutput:
|
|
|
373
433
|
for info in ["user_id", "username", "started_datetime", "worktime_hour"]
|
|
374
434
|
]
|
|
375
435
|
|
|
376
|
-
return
|
|
436
|
+
return (
|
|
437
|
+
base_columns
|
|
438
|
+
+ task_history_columns
|
|
439
|
+
+ [
|
|
440
|
+
"post_rejection_annotation_worktime_hour",
|
|
441
|
+
"post_rejection_inspection_worktime_hour",
|
|
442
|
+
"post_rejection_acceptance_worktime_hour",
|
|
443
|
+
]
|
|
444
|
+
)
|
|
377
445
|
|
|
378
|
-
def output(self, output_path: Path, output_format: FormatArgument)
|
|
446
|
+
def output(self, output_path: Path, output_format: FormatArgument) -> None:
|
|
379
447
|
task_list = self.task_list
|
|
380
448
|
if len(task_list) == 0:
|
|
381
449
|
logger.info("タスク一覧の件数が0件のため、出力しません。")
|
annofabcli/task/put_tasks.py
CHANGED
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import argparse
|
|
4
4
|
import logging
|
|
5
5
|
import multiprocessing
|
|
6
|
+
import sys
|
|
6
7
|
import tempfile
|
|
7
8
|
from collections import defaultdict
|
|
8
9
|
from enum import Enum
|
|
@@ -15,6 +16,7 @@ from annofabapi.models import JobStatus, ProjectJobType, ProjectMemberRole
|
|
|
15
16
|
|
|
16
17
|
import annofabcli
|
|
17
18
|
from annofabcli.common.cli import (
|
|
19
|
+
COMMAND_LINE_ERROR_STATUS_CODE,
|
|
18
20
|
PARALLELISM_CHOICES,
|
|
19
21
|
ArgumentParser,
|
|
20
22
|
CommandLine,
|
|
@@ -230,13 +232,16 @@ class PutTask(CommandLine):
|
|
|
230
232
|
|
|
231
233
|
if args.csv is not None:
|
|
232
234
|
csv_file = args.csv
|
|
233
|
-
|
|
234
|
-
main_obj.generate_task(api_with_creating_task,
|
|
235
|
+
task_relation_dict_from_csv = get_task_relation_dict(csv_file)
|
|
236
|
+
main_obj.generate_task(api_with_creating_task, task_relation_dict_from_csv)
|
|
235
237
|
|
|
236
238
|
elif args.json is not None:
|
|
237
239
|
# CSVファイルに変換する
|
|
238
|
-
|
|
239
|
-
|
|
240
|
+
task_relation_dict_from_json = get_json_from_args(args.json)
|
|
241
|
+
if not isinstance(task_relation_dict_from_json, dict):
|
|
242
|
+
print("annofabcli task put: error: JSON形式が不正です。オブジェクトを指定してください。", file=sys.stderr) # noqa: T201
|
|
243
|
+
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|
|
244
|
+
main_obj.generate_task(api_with_creating_task, task_relation_dict_from_json)
|
|
240
245
|
|
|
241
246
|
|
|
242
247
|
def main(args: argparse.Namespace) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: annofabcli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.99.0
|
|
4
4
|
Summary: Utility Command Line Interface for AnnoFab
|
|
5
5
|
Home-page: https://github.com/kurusugawa-computer/annofab-cli
|
|
6
6
|
License: MIT
|
|
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Topic :: Utilities
|
|
21
21
|
Requires-Dist: Pillow
|
|
22
|
-
Requires-Dist: annofabapi (>=1.1,<2.0)
|
|
22
|
+
Requires-Dist: annofabapi (>=1.4.1,<2.0.0)
|
|
23
23
|
Requires-Dist: bokeh (>=3.3,<3.7)
|
|
24
24
|
Requires-Dist: dictdiffer
|
|
25
25
|
Requires-Dist: isodate
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
annofabcli/__init__.py,sha256=NMA7kFxmLlCiILQPHJa9mEuqXxtLALw_dwyXYsvz4VM,71
|
|
2
2
|
annofabcli/__main__.py,sha256=JzfycqVG9ENhWOCxTouZwpHwWTSrI-grLsaMudxjyBM,5283
|
|
3
|
-
annofabcli/__version__.py,sha256=
|
|
3
|
+
annofabcli/__version__.py,sha256=3vcSVu6yWUIItVt25unwZ7jMczwQM4BnBXs-Kszfrkc,132
|
|
4
4
|
annofabcli/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
annofabcli/annotation/annotation_query.py,sha256=ke3W3RT1-WfFzwt-TXcQwGmghG34vcKJkM_jxgbNKjU,15922
|
|
6
6
|
annofabcli/annotation/change_annotation_attributes.py,sha256=zHXyENZfbMGL_15xiK7Cy4cQ2sV0GjSVmKuPm3sOX7Y,17173
|
|
@@ -12,8 +12,10 @@ annofabcli/annotation/dump_annotation.py,sha256=YIl9eP6cfvMcE13CLooZO7siHzotc67b
|
|
|
12
12
|
annofabcli/annotation/import_annotation.py,sha256=BlGAcXF9T19Ea1wtplUMPrOfiWYLBajK2XizOctdUtA,29304
|
|
13
13
|
annofabcli/annotation/list_annotation.py,sha256=B8ZFI7SRQPy-TgbpaX-tzXhveViY17YuCPE9BuK9mrs,10790
|
|
14
14
|
annofabcli/annotation/list_annotation_count.py,sha256=T9fbaoxWeDJIVgW_YgHRldbwrVZWiE-57lfJrDQrj80,6474
|
|
15
|
+
annofabcli/annotation/merge_segmentation.py,sha256=ldEQlcyCrog0KFYn92sTkScZQ7gmTjlujuCsKBemjhU,17950
|
|
16
|
+
annofabcli/annotation/remove_segmentation_overlap.py,sha256=gONYqaI0PMEGYJduB4JsmGBn3LCY9JtLSFgosWYyc3M,15957
|
|
15
17
|
annofabcli/annotation/restore_annotation.py,sha256=naUEbt48ION9JSijCBR2aQdaoCrRu005tYq0vgUtyp0,14683
|
|
16
|
-
annofabcli/annotation/subcommand_annotation.py,sha256=
|
|
18
|
+
annofabcli/annotation/subcommand_annotation.py,sha256=ku9mzb7zZilHcjf1MFV1E7EJ8OvfSUDHpcunM38teto,2122
|
|
17
19
|
annofabcli/annotation_specs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
20
|
annofabcli/annotation_specs/export_annotation_specs.py,sha256=eZF5fj2P5U22_5UKgbpsUhZEUvVPMPerMpN4miIcnSA,4821
|
|
19
21
|
annofabcli/annotation_specs/get_annotation_specs_with_attribute_id_replaced.py,sha256=L0H0M31Amnm3ZEg9JdQe2A1vprsCLPTpj0LUFnP6GDY,8330
|
|
@@ -25,18 +27,18 @@ annofabcli/annotation_specs/list_annotation_specs_history.py,sha256=DtF8X8hA3N54
|
|
|
25
27
|
annofabcli/annotation_specs/list_annotation_specs_label.py,sha256=5k7lDJS1oCi1JS0sLsjyczQ_9W5-jR2AOrZn8dAx1ys,11755
|
|
26
28
|
annofabcli/annotation_specs/list_attribute_restriction.py,sha256=J1QhnUwRX09KRv2Gn7J_BITJu3IuIL3tkYe8CWcyQAw,14740
|
|
27
29
|
annofabcli/annotation_specs/list_label_color.py,sha256=huHBAb-LVLe-tj5ZALiBkFgZlZSTvi2ZDsPYgJPDZ2Q,2356
|
|
28
|
-
annofabcli/annotation_specs/put_label_color.py,sha256=
|
|
30
|
+
annofabcli/annotation_specs/put_label_color.py,sha256=HJTczQiE7uwdnpHh0Lyz_WuvtyXOxYt8RThBXpvjKgA,6057
|
|
29
31
|
annofabcli/annotation_specs/subcommand_annotation_specs.py,sha256=lhs4M5KHSGA59z-XsDuzFascZNbPxq-QnPHrUcntMf4,2384
|
|
30
32
|
annofabcli/comment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
annofabcli/comment/delete_comment.py,sha256=
|
|
33
|
+
annofabcli/comment/delete_comment.py,sha256=EsQtUCq-HZtYmHQiXq4KbkgjqS4NPlC44MJQKgUzhnY,11458
|
|
32
34
|
annofabcli/comment/download_comment_json.py,sha256=YfqUnMgvLgVFV7FJPIXwirREkQ2E63fXeCaF4hfwk8c,2338
|
|
33
35
|
annofabcli/comment/list_all_comment.py,sha256=p5STKKQ4SV-vDvY1F3pKOrveZcteLTHIUEO-ci1nGes,6090
|
|
34
36
|
annofabcli/comment/list_comment.py,sha256=gZSzeBeYLt0dhCi-8GcuEEB1NuJoXRdptp4oxkOtAMQ,4947
|
|
35
37
|
annofabcli/comment/put_comment.py,sha256=yrxCtP9JkPvBtmZZ3vbm8XFYNKBTgwKwfGcauVvu5e8,12144
|
|
36
38
|
annofabcli/comment/put_comment_simply.py,sha256=Y_RSKWMs8j5VAVV8iiJOOBHnJHEH5s3HLJrXnmmQT3o,8184
|
|
37
|
-
annofabcli/comment/put_inspection_comment.py,sha256=
|
|
39
|
+
annofabcli/comment/put_inspection_comment.py,sha256=F7m6lsbN0FHk0adwiapvD2UOv-8fbCdqfA9CtuJcnY8,3869
|
|
38
40
|
annofabcli/comment/put_inspection_comment_simply.py,sha256=6oKYuihsOKkAKMzcLeUzgMu9SIJC9fWzM1VBis3asfo,6870
|
|
39
|
-
annofabcli/comment/put_onhold_comment.py,sha256=
|
|
41
|
+
annofabcli/comment/put_onhold_comment.py,sha256=9tJ6zzOwqr80SqCSyPFEyqkWpVahHvEEsWIaHxPrB-A,3529
|
|
40
42
|
annofabcli/comment/put_onhold_comment_simply.py,sha256=8w-E8aIK2SbHI9pnsfGF6IlVGC8qDt60Yjrr7Hfz1Rw,3308
|
|
41
43
|
annofabcli/comment/subcommand_comment.py,sha256=gd8w8ArXM1Tq9VUduDgn8m4G6HwevRWJ36VBtGHg-5I,1537
|
|
42
44
|
annofabcli/comment/utils.py,sha256=aUj7U6MtGh64F3Ko83y4NKPKyWAqcg-c1XLqjkmIpSk,350
|
|
@@ -67,7 +69,7 @@ annofabcli/filesystem/mask_user_info.py,sha256=Evmr9QhSpMG900bbOXbJNHwXHapUlNfvV
|
|
|
67
69
|
annofabcli/filesystem/merge_annotation.py,sha256=MkGy1T9F-1tHq_BS_L_mTtgKpOMmXscrydzfSc0JKAo,10588
|
|
68
70
|
annofabcli/filesystem/subcommand_filesystem.py,sha256=ZM2td5iZYIQ3TCI-9xAue8LugFlIc3WMRXrJqnjJ8-s,1186
|
|
69
71
|
annofabcli/input_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
-
annofabcli/input_data/change_input_data_name.py,sha256=
|
|
72
|
+
annofabcli/input_data/change_input_data_name.py,sha256=cQWoGTZKwr2_fU1WGALmRyJY39ruf9t4eMxpI06eT9g,9943
|
|
71
73
|
annofabcli/input_data/copy_input_data.py,sha256=Lbyq2aW5lmJCPB8-WHdOI93a2ND5E0qOWrhBHRluQyw,14656
|
|
72
74
|
annofabcli/input_data/delete_input_data.py,sha256=GLg58XNz9_Njq9eq2sc2BAzfLy9tJefcDYL6J4TOim4,8836
|
|
73
75
|
annofabcli/input_data/delete_metadata_key_of_input_data.py,sha256=PVv9HXQVFLKQh-4RSHas_ckFxDxtqAzWnXnWYFFYy08,8464
|
|
@@ -75,7 +77,7 @@ annofabcli/input_data/download_input_data_json.py,sha256=vxGoeM3ZEggQbWiWsrDK0_G
|
|
|
75
77
|
annofabcli/input_data/list_all_input_data.py,sha256=Kq261WCkma5UNKfMDT7O6Z-dzzqp-KP1wL0DvHe5fH8,9879
|
|
76
78
|
annofabcli/input_data/list_all_input_data_merged_task.py,sha256=UaBJW-nMHytmQ4okg69Ew1jhC2vMNnRMgl2lEBabtUI,12850
|
|
77
79
|
annofabcli/input_data/list_input_data.py,sha256=RBxsHyKg1bVIEQUFDkfrq-nJmEdEYNoCjJ2L2GgSfeU,11519
|
|
78
|
-
annofabcli/input_data/put_input_data.py,sha256=
|
|
80
|
+
annofabcli/input_data/put_input_data.py,sha256=QrIe_RBXfGzpTYazy4cN8iSdHTQjq96sI0bXq6g1G_k,18233
|
|
79
81
|
annofabcli/input_data/put_input_data_with_zip.py,sha256=SA4aMAwMBFgc9Lh0zmRCbmkXG4AMrcBqd5zeTSdr8lc,5566
|
|
80
82
|
annofabcli/input_data/subcommand_input_data.py,sha256=X8EoxsF6PMiKrvk_r7PIe2D0WZuaPlgLJRuTiljPIdM,2048
|
|
81
83
|
annofabcli/input_data/update_metadata_of_input_data.py,sha256=_cZh0GYGK6Lx5arKuTjblolkXsRdTlwuKcIHa8Nm5yQ,11583
|
|
@@ -131,12 +133,13 @@ annofabcli/statistics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
|
131
133
|
annofabcli/statistics/histogram.py,sha256=CvzDxT2cKLSnBGSqkZE6p92PayGxYYja1YyB24M4ALU,3245
|
|
132
134
|
annofabcli/statistics/linegraph.py,sha256=0kr7jVBNMiM2ECYhv3Ry5RitElKerSl9ZKxbKzfiplI,12494
|
|
133
135
|
annofabcli/statistics/list_annotation_attribute.py,sha256=87jjNCOXJUbWnmswMCLN7GTjGsBfqpFJ6hViWmnj8Y4,12557
|
|
134
|
-
annofabcli/statistics/
|
|
135
|
-
annofabcli/statistics/
|
|
136
|
+
annofabcli/statistics/list_annotation_attribute_filled_count.py,sha256=vwWeFHwTnEMdrLBauIKPFDkUCa6lXXd0GQgUAQ0LCqU,28890
|
|
137
|
+
annofabcli/statistics/list_annotation_count.py,sha256=nzmlHRCWt5mjeksZkeQyWqm4UaCa9SrdbNtuX9TPP5w,52907
|
|
138
|
+
annofabcli/statistics/list_annotation_duration.py,sha256=N7nnVUDfX_thIapqe6-z_MqReiIqNS8rhp6ewRnvXBU,32027
|
|
136
139
|
annofabcli/statistics/list_video_duration.py,sha256=uNeMteRBX2JG_AWmcgMJj0Jzbq_qF7bvAwr25GmeIiw,9124
|
|
137
140
|
annofabcli/statistics/list_worktime.py,sha256=C7Yu3IOW2EvhkJJv6gY3hNdS9_TOLmT_9LZsB7vLJ1o,6493
|
|
138
141
|
annofabcli/statistics/scatter.py,sha256=IUCwXix9GbZb6V82wjjb5q2eamrT5HQsU_bzDTjAFnM,11011
|
|
139
|
-
annofabcli/statistics/subcommand_statistics.py,sha256=
|
|
142
|
+
annofabcli/statistics/subcommand_statistics.py,sha256=mx18Fgxz2eG4LrF-x0vISw2qh9aLommxuQLD8cfoZhw,2416
|
|
140
143
|
annofabcli/statistics/summarize_task_count.py,sha256=8OH6BBRYRjHJkWRTjU0A0OfXa7f3NIRHrxPNFlRt_hM,9707
|
|
141
144
|
annofabcli/statistics/summarize_task_count_by_task_id_group.py,sha256=TSSmcFv615NLcq6uqXmg3ilYqSHl3A5qp90msVQM1gE,8646
|
|
142
145
|
annofabcli/statistics/summarize_task_count_by_user.py,sha256=TRoJXpt2HOVb8QO2YtRejkOAxyK80_NsPt3Vk9es9C8,6948
|
|
@@ -150,7 +153,7 @@ annofabcli/statistics/visualization/dataframe/input_data_count.py,sha256=wDRFtoI
|
|
|
150
153
|
annofabcli/statistics/visualization/dataframe/inspection_comment_count.py,sha256=RxpQzRy4U2hKEpgbksUXotcxH2sKz__NO20mxpMqK1w,4382
|
|
151
154
|
annofabcli/statistics/visualization/dataframe/productivity_per_date.py,sha256=tMap7E3z7hibon1zJnZRJnbMmtzqh04ocoV0oxBpssU,27249
|
|
152
155
|
annofabcli/statistics/visualization/dataframe/project_performance.py,sha256=hdTMPvLfGDMZFjpIl58GtTEOopsOvitbdaj5hQAEp8o,8496
|
|
153
|
-
annofabcli/statistics/visualization/dataframe/task.py,sha256=
|
|
156
|
+
annofabcli/statistics/visualization/dataframe/task.py,sha256=Heb0sx7T6KI422aFVKQUCP2wqD_czpM4KMsgqb4wjVw,24269
|
|
154
157
|
annofabcli/statistics/visualization/dataframe/task_history.py,sha256=3b9e4ok6yKE5x647KzRqvp01P33XMAHLEEbLJ5GCmRo,2760
|
|
155
158
|
annofabcli/statistics/visualization/dataframe/task_worktime_by_phase_user.py,sha256=AtlbeNIkttjLtuxtZYCyZin4eVKRvcYEMnLzEZtZUlY,13134
|
|
156
159
|
annofabcli/statistics/visualization/dataframe/user.py,sha256=EHn7nlf6D6UX-gsVXy8m_3QaCsHsUhr0iy2rbNozOgc,1707
|
|
@@ -184,8 +187,8 @@ annofabcli/task/download_task_json.py,sha256=Ocjecmdf2WV_Sq3u1InfMLIsT3XSw0ojyJm
|
|
|
184
187
|
annofabcli/task/list_all_tasks.py,sha256=F9GpzzgWffF3lUeGrFIvjweq-iEwJ1c-g8usskO_2dE,6506
|
|
185
188
|
annofabcli/task/list_all_tasks_added_task_history.py,sha256=fkdiuo64iS7xxvIfGKzSiUPPEMiCVnJjjcAtMxe2Ngs,9551
|
|
186
189
|
annofabcli/task/list_tasks.py,sha256=O4jjp_zdmurcGNWXFp9JXHJsH4nhlR5e3ok96YnD1SI,10237
|
|
187
|
-
annofabcli/task/list_tasks_added_task_history.py,sha256=
|
|
188
|
-
annofabcli/task/put_tasks.py,sha256=
|
|
190
|
+
annofabcli/task/list_tasks_added_task_history.py,sha256=Yjvv5fJjSjJ-v9bhwl4PDyU8aeT94LLMBcPhmUWlFUI,21639
|
|
191
|
+
annofabcli/task/put_tasks.py,sha256=c_Vw5qnDlfpa21S-aMVxmXy8pF-z_YEUi6a0c3IV9gc,13770
|
|
189
192
|
annofabcli/task/put_tasks_by_count.py,sha256=MUHfWhqtSAXnB3O36p3bMSSgQ_3Zek9GT5qRvHGx8Lo,6041
|
|
190
193
|
annofabcli/task/reject_tasks.py,sha256=5ByAN6VnKwvU5BT_cfsHwA1jLDl74bonqk3bwtnrkPU,23139
|
|
191
194
|
annofabcli/task/subcommand_task.py,sha256=L_5Dwe58eblrtOrUYxjJAvkSmu6savRUxIqGjsFq-R4,2436
|
|
@@ -200,8 +203,8 @@ annofabcli/task_history_event/download_task_history_event_json.py,sha256=hQLVbQ0
|
|
|
200
203
|
annofabcli/task_history_event/list_all_task_history_event.py,sha256=JQEgwOIXbbTIfeX23AVaoySHViOR9UGm9uoXuhVEBqo,6446
|
|
201
204
|
annofabcli/task_history_event/list_worktime.py,sha256=9jsRYa2C9bva8E1Aqxv9CCKDuCP0MvbiaIyQFTDpjqY,13150
|
|
202
205
|
annofabcli/task_history_event/subcommand_task_history_event.py,sha256=mJVJoT4RXk4HWnY7-Nrsl4If-gtaIIEXd2z7eFZwM2I,1260
|
|
203
|
-
annofabcli-1.
|
|
204
|
-
annofabcli-1.
|
|
205
|
-
annofabcli-1.
|
|
206
|
-
annofabcli-1.
|
|
207
|
-
annofabcli-1.
|
|
206
|
+
annofabcli-1.99.0.dist-info/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
|
|
207
|
+
annofabcli-1.99.0.dist-info/METADATA,sha256=YTn2PV9tc0pWHXD1sQ88yiulbIhZc29WlLIOcz9jCE4,5630
|
|
208
|
+
annofabcli-1.99.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
209
|
+
annofabcli-1.99.0.dist-info/entry_points.txt,sha256=A8vlN9fiMhbYRcdBfSpl7piYzAwvkMhRXIPQUAvQFUo,55
|
|
210
|
+
annofabcli-1.99.0.dist-info/RECORD,,
|