Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 71 additions & 1 deletion annofabapi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
import datetime
import logging
from pathlib import Path
from typing import Optional
from typing import List, Optional

import dateutil
import dateutil.tz
import requests

from annofabapi.models import TaskHistory, TaskPhase


def raise_for_status(response: requests.Response):
"""
Expand Down Expand Up @@ -131,3 +133,71 @@ def wrapped(*args, **kwargs):
logging.getLogger("backoff").setLevel(level=backoff_logger_level)

return wrapped


def get_task_history_index_skipped_acceptance(task_history_list: List[TaskHistory]) -> List[int]:
"""
受入がスキップされたタスク履歴のインデックス番号(0始まり)を返す。
Args:
task_history_list: タスク履歴List
Returns:
受入フェーズがスキップされた履歴のインデックス番号(0始まり)。受入がスキップされていない場合は空リストを返す。
"""
index_list = []
for index, history in enumerate(task_history_list):
if not (TaskPhase(history["phase"]) == TaskPhase.ACCEPTANCE and history["account_id"] is None
and history["accumulated_labor_time_milliseconds"] == "PT0S" and history["started_datetime"] is not None
and history["ended_datetime"] is not None):
continue

if index + 1 < len(task_history_list):
# 直後の履歴あり
next_history = task_history_list[index + 1]
if TaskPhase(next_history["phase"]) in [TaskPhase.ANNOTATION, TaskPhase.INSPECTION]:
# 教師付フェーズ or 検査フェーズでの提出取消(直後が前段のフェーズ)
pass
else:
# 受入スキップ
index_list.append(index)
else:
# 直後の履歴がない
index_list.append(index)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最後の履歴が受入フェーズで担当者なしというのは、受入未着手も含まれるのでは?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

「受入フェーズで担当者なし」のタスクは、受入フェーズのタスク履歴がなかったため、問題ないかと思います。
「受入フェーズの担当者が割り当てられた」タスクは、受入フェーズのタスク履歴がありました。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

とはいえ、「started_datetimeended_datetime`の両方がnullである」という条件を加えた方が確実だと思ったので、修正します。


return index_list


def get_task_history_index_skipped_inspection(task_history_list: List[TaskHistory]) -> List[int]:
"""
検査フェーズがスキップされたタスク履歴のインデックス番号(0始まり)を返す。
Args:
task_history_list: タスク履歴List
Returns:
検査フェーズがスキップされた履歴のインデックス番号(0始まり)。検査がスキップされていない場合は空リストを返す。
"""
index_list = []
for index, history in enumerate(task_history_list):
if not (TaskPhase(history["phase"]) == TaskPhase.INSPECTION and history["account_id"] is None
and history["accumulated_labor_time_milliseconds"] == "PT0S" and history["started_datetime"] is not None
and history["ended_datetime"] is not None):
continue

if index + 1 < len(task_history_list):
# 直後の履歴あり
next_history = task_history_list[index + 1]
if TaskPhase(next_history["phase"]) in [TaskPhase.ANNOTATION, TaskPhase.INSPECTION]:
# 教師付フェーズ or 検査フェーズでの提出取消(直後が前段のフェーズ)
pass
else:
# 検査スキップ
index_list.append(index)
else:
# 直後の履歴がない
index_list.append(index)

return index_list
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ split_before_named_assigns = False
[flake8]
max-line-length = 120
# F401: 'xxxx' imported but unused
ignore = F401
ignore = F401, W503

[mypy]
ignore_missing_imports = True
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Topic :: Utilities",
"Operating System :: OS Independent",
],
Expand Down
233 changes: 233 additions & 0 deletions tests/test_local_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,236 @@
# d = datetime.datetime(2019, 10, 8, 16, 20, 8, 241762)
# tz_jst = datetime.timezone(datetime.timedelta(hours=9))
# assert to_iso8601_extension(d, tz_jst) == "2019-10-08T16:20:08.241+09:00"

from annofabapi.utils import get_task_history_index_skipped_acceptance, get_task_history_index_skipped_inspection


class TestTaskHistoryUtils:
ACCOUNT_ID = "12345678-abcd-1234-abcd-1234abcd5678"

def test_get_task_history_index_skipped_acceptance_検査0回_受入スキップ(self):
task_history_list = [{
"started_datetime": "2020-01-22T09:32:15.284+09:00",
"ended_datetime": "2020-01-22T09:32:19.628+09:00",
"accumulated_labor_time_milliseconds": "PT4.344S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T09:32:19.63+09:00",
"ended_datetime": "2020-01-22T09:32:19.63+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "acceptance",
"phase_stage": 1,
"account_id": None
}]

actual = get_task_history_index_skipped_acceptance(task_history_list)
expected = [1]
assert all([a == b for a, b in zip(actual, expected)])

def test_get_task_history_index_skipped_acceptance_検査0回_受入スキップ後に受入取消(self):
task_history_list = [{
"started_datetime": "2020-01-22T09:35:26.13+09:00",
"ended_datetime": "2020-01-22T09:35:29.745+09:00",
"accumulated_labor_time_milliseconds": "PT3.615S",
"phase": "annotation",
"phase_stage": 1,
"account_id": "00589ed0-dd63-40db-abb2-dfe5e13c8299"
}, {
"started_datetime": "2020-01-22T09:35:29.747+09:00",
"ended_datetime": "2020-01-22T09:35:29.747+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "acceptance",
"phase_stage": 1,
"account_id": None
}, {
"started_datetime": None,
"ended_datetime": None,
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "acceptance",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}]

actual = get_task_history_index_skipped_acceptance(task_history_list)
expected = [1]
assert all([a == b for a, b in zip(actual, expected)])

def test_get_task_history_index_skipped_acceptance_検査0回_教師付で提出取消(self):
task_history_list = [{
"started_datetime": "2020-01-22T09:36:11.187+09:00",
"ended_datetime": "2020-01-22T09:36:14.186+09:00",
"accumulated_labor_time_milliseconds": "PT2.999S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T09:36:23.86+09:00",
"ended_datetime": "2020-01-22T09:36:23.86+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "acceptance",
"phase_stage": 1,
"account_id": None
}, {
"started_datetime": None,
"ended_datetime": None,
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}]
actual = get_task_history_index_skipped_acceptance(task_history_list)
expected = []
assert all([a == b for a, b in zip(actual, expected)])

def test_get_task_history_index_skipped_acceptance_検査1回_検査で提出取消(self):
task_history_list = [{
"started_datetime": "2020-01-22T09:39:20.492+09:00",
"ended_datetime": "2020-01-22T09:39:24.911+09:00",
"accumulated_labor_time_milliseconds": "PT4.419S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T09:40:04.978+09:00",
"ended_datetime": "2020-01-22T09:40:08.091+09:00",
"accumulated_labor_time_milliseconds": "PT3.113S",
"phase": "inspection",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T09:40:15.136+09:00",
"ended_datetime": "2020-01-22T09:40:15.136+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "acceptance",
"phase_stage": 1,
"account_id": None
}, {
"started_datetime": None,
"ended_datetime": None,
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "inspection",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}]

actual = get_task_history_index_skipped_acceptance(task_history_list)
expected = []
assert all([a == b for a, b in zip(actual, expected)])

def test_get_task_history_index_skipped_inspection_検査1回_検査スキップ(self):
task_history_list = [{
"started_datetime": "2020-01-22T09:58:20.063+09:00",
"ended_datetime": "2020-01-22T09:58:23.749+09:00",
"accumulated_labor_time_milliseconds": "PT3.686S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T09:58:23.751+09:00",
"ended_datetime": "2020-01-22T09:58:23.751+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "inspection",
"phase_stage": 1,
"account_id": None
}, {
"started_datetime": "2020-01-22T09:58:23.753+09:00",
"ended_datetime": "2020-01-22T09:58:23.753+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "acceptance",
"phase_stage": 1,
"account_id": None
}]

actual = get_task_history_index_skipped_inspection(task_history_list)
expected = [1]
assert all([a == b for a, b in zip(actual, expected)])

def test_get_task_history_index_skipped_inspection_検査1回_教師付で提出取消(self):
task_history_list = [{
"started_datetime": "2020-01-22T10:00:33.832+09:00",
"ended_datetime": "2020-01-22T10:00:37.381+09:00",
"accumulated_labor_time_milliseconds": "PT3.549S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T10:00:45.953+09:00",
"ended_datetime": "2020-01-22T10:00:45.953+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "inspection",
"phase_stage": 1,
"account_id": None
}, {
"started_datetime": None,
"ended_datetime": None,
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}]
actual = get_task_history_index_skipped_inspection(task_history_list)
expected = []
assert all([a == b for a, b in zip(actual, expected)])

def test_get_task_history_index_skipped_inspection_検査1回_教師付で提出取消(self):
task_history_list = [{
"started_datetime": "2020-01-22T10:00:33.832+09:00",
"ended_datetime": "2020-01-22T10:00:37.381+09:00",
"accumulated_labor_time_milliseconds": "PT3.549S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T10:00:45.953+09:00",
"ended_datetime": "2020-01-22T10:00:45.953+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "inspection",
"phase_stage": 1,
"account_id": None
}, {
"started_datetime": None,
"ended_datetime": None,
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}]
actual = get_task_history_index_skipped_inspection(task_history_list)
expected = []
assert all([a == b for a, b in zip(actual, expected)])

def test_get_task_history_index_skipped_inspection_検査2回_検査1回目で提出取消(self):
task_history_list = [{
"started_datetime": "2019-09-04T16:15:51.505+09:00",
"ended_datetime": "2019-09-04T16:16:31.597+09:00",
"accumulated_labor_time_milliseconds": "PT40.092S",
"phase": "annotation",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T10:06:18.435+09:00",
"ended_datetime": "2020-01-22T10:06:21.919+09:00",
"accumulated_labor_time_milliseconds": "PT3.484S",
"phase": "inspection",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}, {
"started_datetime": "2020-01-22T10:07:38.456+09:00",
"ended_datetime": "2020-01-22T10:07:38.456+09:00",
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "inspection",
"phase_stage": 2,
"account_id": None
}, {
"started_datetime": None,
"ended_datetime": None,
"accumulated_labor_time_milliseconds": "PT0S",
"phase": "inspection",
"phase_stage": 1,
"account_id": self.ACCOUNT_ID
}]
actual = get_task_history_index_skipped_inspection(task_history_list)
expected = []
assert all([a == b for a, b in zip(actual, expected)])