Skip to content

Commit

Permalink
Merge pull request #100 from kurusugawa-computer/fix/statistics
Browse files Browse the repository at this point in the history
統計情報可視化コマンドの修正
  • Loading branch information
yuji38kwmt authored Oct 23, 2019
2 parents 5fe8294 + 6755ecb commit 79f2c69
Show file tree
Hide file tree
Showing 14 changed files with 494 additions and 189 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ language: python
python:
- "3.6"
- "3.7"
- "3.8"
install:
- pip install . flake8 mypy pylint pytest
script:
- flake8 annofabcli
- mypy annofabcli --config-file setup.cfg
- pylint annofabcli --rcfile setup.cfg
- pytest tests/test_local*.py
branches:
only:
- master
200 changes: 111 additions & 89 deletions Pipfile.lock

Large diffs are not rendered by default.

27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ $ docker run -it -e ANNOFAB_USER_ID=XXXX -e ANNOFAB_PASSWORD=YYYYY annofab-cli a
|inspection_comment| list_unprocessed | 未処置の検査コメントを出力します。 |-|
|instruction| upload | HTMLファイルを作業ガイドとして登録します。 |チェッカー/オーナ|
|job|list | ジョブ一覧を出力します。 |-|
|job|list_last | 複数のプロジェクトに対して、最新のジョブを出力します。 |-|
|organization_member|list | 組織メンバ一覧を出力します。 |-|
|project| copy | プロジェクトをコピーします。 |オーナ and 組織管理者/組織オーナ|
|project| diff | プロジェクト間の差分を表示します。 |チェッカー/オーナ|
Expand Down Expand Up @@ -622,6 +623,25 @@ $ annofabcli job list --project_id prj1 --job_type gen-tasks --job_query '{"limi
### job list_last
複数のプロジェクトに対して、最新のジョブを出力します。
```
# prj1, prj2に対して、「アノテーション更新」のジョブを出力します。
$ annofabcli job list_last --project_id prj1 prj2 --job_type gen-annotation

# 組織 org1配下のプロジェクト(進行中で、自分自身が所属している)に対して、「タスク全件ファイル更新」のジョブを出力します。
$ annofabcli job list_last --organization org1 --job_type gen-tasks-list

# アノテーションの最終更新日時を、タスクの最終更新日時と比較して出力します。
$ annofabcli job list_last --project_id prj1 --job_type gen-annotation --add_details \
--csv_format '{"columns": ["project_id","project_title","job_status","updated_datetime", "task_last_updated_datetime"]}'

```
### organization_member list
組織メンバ一覧を出力します。
Expand Down Expand Up @@ -865,8 +885,13 @@ $ annofabcli statistics visualize --project_id prj1 --output_dir /tmp/output
$ annofabcli statistics visualize --project_id prj1 --output_dir /tmp/output \
--task_query '{"status": "complete"}'

# 作業ディレクトリ(`.annofab-cli`)内のファイルから、統計情報を可視化する。
# アノテーションzipを更新してから、アノテーションzipをダウンロードします。
$ annofabcli statistics visualize --project_id prj1 --output_dir /tmp/output --update_annotation


# WebAPIを実行せずに、作業ディレクトリ(`.annofab-cli`)内のファイルを参照して、統計情報を可視化する。
$ annofabcli statistics visualize --project_id prj1 --not_update

```
Expand Down
2 changes: 1 addition & 1 deletion annofabcli/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.11.0'
__version__ = '1.12.0'
1 change: 0 additions & 1 deletion annofabcli/common/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ def get_list_from_args(str_list: Optional[List[str]] = None) -> List[str]:
文字列のListのサイズが1で、プレフィックスが`file://`ならば、ファイルパスとしてファイルを読み込み、行をListとして返す。
そうでなければ、引数の値をそのままかえす。
ただしNoneの場合は空Listを変えす
Listが1小
"""
if str_list is None or len(str_list) == 0:
return []
Expand Down
2 changes: 1 addition & 1 deletion annofabcli/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def isoduration_to_hour(duration):

def allow_404_error(function):
"""
Not Found Errorを無視(許容)して、処理する。
Not Found Error(404)を無視(許容)して、処理する。Not Foundのとき戻りはNoneになる
リソースの存在確認などに利用する。
try-exceptを行う。また404 Errorが発生したときのエラーログを無効化する
"""
Expand Down
2 changes: 1 addition & 1 deletion annofabcli/job/list_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def parse_args(parser: argparse.ArgumentParser):
job_choices = [e.value for e in JobType]
argument_parser.add_project_id()

parser.add_argument('--job_type', type=str, choices=job_choices, help='ジョブタイプを指定します。')
parser.add_argument('--job_type', type=str, choices=job_choices, required=True, help='ジョブタイプを指定します。')

# クエリがうまく動かないので、コメントアウトする
# parser.add_argument(
Expand Down
169 changes: 169 additions & 0 deletions annofabcli/job/list_last_job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import argparse
import logging
import sys
from typing import Any, Callable, Dict, List, Optional, Tuple, Union # pylint: disable=unused-import

from annofabapi.models import JobInfo, JobType, Project

import annofabcli
from annofabcli import AnnofabApiFacade
from annofabcli.common.cli import AbstractCommandLineInterface, ArgumentParser, build_annofabapi_resource_and_login
from annofabcli.common.enums import FormatArgument

logger = logging.getLogger(__name__)


class ListLastJob(AbstractCommandLineInterface):
"""
ジョブ一覧を表示する。
"""
def get_last_job(self, project_id: str, job_type: JobType) -> Optional[JobInfo]:
"""
最新のジョブを取得する。ジョブが存在しない場合はNoneを返す。
"""
query_params = {"type": job_type.value}
content, _ = self.service.api.get_project_job(project_id, query_params)
job_list = content["list"]
if len(job_list) == 0:
logger.info(f"project_id={project_id}にjob_type={job_type.value}のジョブは存在しませんでした。")
return None
else:
return job_list[-1]

def add_properties_to_job(self, job: JobInfo, project_id: str, add_details: bool = False,
project: Optional[Project] = None) -> JobInfo:
"""
ジョブ情報にプロパティを追加する。
Args:
project_id:
job:
add_details:
Returns:
"""
if project is None:
project, _ = self.service.api.get_project(project_id)

job["project_title"] = project["title"]

if add_details:
job["task_last_updated_datetime"] = project["summary"]["last_tasks_updated_datetime"]

annotation_specs_history = self.service.api.get_annotation_specs_histories(project_id)[0]
job["annotation_specs_last_updated_datetime"] = annotation_specs_history[-1]["updated_datetime"]

return job

@annofabcli.utils.allow_404_error
def get_project(self, project_id: str) -> Project:
project, _ = self.service.api.get_project(project_id)
return project

def get_last_job_list(self, project_id_list: List[str], job_type: JobType,
add_details: bool = False) -> List[JobInfo]:
job_list = []

for project_id in project_id_list:
project = self.get_project(project_id)

if project is None:
logger.warning(f"project_id='{project_id}' のプロジェクトは存在しませんでした。")
continue

job = self.get_last_job(project_id, job_type)
if job is None:
job = {"project_id": project_id, "project_title": project["title"]}
else:
job = self.add_properties_to_job(job, project_id=project_id, add_details=add_details, project=project)

job_list.append(job)

return job_list

def print_job_list(self, project_id_list: List[str], job_type: JobType, add_details: bool = False) -> None:
"""
ジョブ一覧を出力する
Args:
project_id: 対象のproject_id
job_type: ジョブタイプ
"""

job_list = self.get_last_job_list(project_id_list, job_type=job_type, add_details=add_details)
logger.info(f"{len(job_list)} 個のプロジェクトの, job_type={job_type.value} の最新ジョブを出力します。")
self.print_according_to_format(job_list)

def get_project_id_list(self, organization_name: str) -> List[str]:
"""
進行中で自分自身が所属する project_id を取得する
Args:
organization_name:
Returns:
"""
my_account, _ = self.service.api.get_my_account()
query_params = {"status": "active", "account_id": my_account["account_id"]}
project_list = self.service.wrapper.get_all_projects_of_organization(organization_name,
query_params=query_params)
return [e["project_id"] for e in project_list]

def main(self):
args = self.args
job_type = JobType(args.job_type)

if args.organization is not None:
project_id_list = self.get_project_id_list(args.organization)

elif args.project_id is not None:
project_id_list = annofabcli.common.cli.get_list_from_args(args.project_id)

else:
print("引数に`--project_id` または `--organization` を指定してください。", file=sys.stderr)
return

self.print_job_list(project_id_list, job_type=job_type, add_details=args.add_details)


def main(args):
service = build_annofabapi_resource_and_login()
facade = AnnofabApiFacade(service)
ListLastJob(service, facade, args).main()


def parse_args(parser: argparse.ArgumentParser):
argument_parser = ArgumentParser(parser)

job_choices = [e.value for e in JobType]
parser.add_argument('--job_type', type=str, choices=job_choices, required=True, help='ジョブタイプを指定します。')

list_group = parser.add_mutually_exclusive_group(required=True)
list_group.add_argument('-p', '--project_id', type=str, nargs='+',
help='対象のプロジェクトのproject_idを指定してください。`file://`を先頭に付けると、一覧が記載されたファイルを指定できます。')

list_group.add_argument('-org', '--organization', type=str, help='組織配下のすべてのプロジェクトのジョブを出力したい場合は、組織名を指定してください。')

parser.add_argument(
'--add_details', action='store_true', help='プロジェクトに関する詳細情報を表示します'
'(`task_last_updated_datetime, annotation_specs_last_updated_datetime`)')

argument_parser.add_format(choices=[FormatArgument.CSV, FormatArgument.JSON, FormatArgument.PRETTY_JSON],
default=FormatArgument.CSV)
argument_parser.add_output()
argument_parser.add_csv_format()

argument_parser.add_query()
parser.set_defaults(subcommand_func=main)


def add_parser(subparsers: argparse._SubParsersAction):
subcommand_name = "list_last"
subcommand_help = "複数のプロジェクトに対して、最新のジョブを出力します。"
description = ("複数のプロジェクトに対して、最新のジョブを出力します。")

parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
parse_args(parser)
2 changes: 2 additions & 0 deletions annofabcli/job/subcommand_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import annofabcli
import annofabcli.common.cli
import annofabcli.job.list_job
import annofabcli.job.list_last_job


def parse_args(parser: argparse.ArgumentParser):
Expand All @@ -11,6 +12,7 @@ def parse_args(parser: argparse.ArgumentParser):

# サブコマンドの定義
annofabcli.job.list_job.add_parser(subparsers)
annofabcli.job.list_last_job.add_parser(subparsers)


def add_parser(subparsers: argparse._SubParsersAction):
Expand Down
3 changes: 2 additions & 1 deletion annofabcli/project/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ def download(self, target: DownloadTarget, project_id: str, output: str, latest:
if latest:
self.service.api.post_project_tasks_update(project_id)
result = self.service.wrapper.wait_for_completion(project_id, job_type=JobType.GEN_TASKS_LIST,
job_access_interval=60, max_job_access=30)
job_access_interval=JOB_ACCESS_INTERVAL,
max_job_access=MAX_JOB_ACCESS)
if result:
logger.info(f"タスクファイルの更新が完了しました。")
else:
Expand Down
Loading

0 comments on commit 79f2c69

Please sign in to comment.