Skip to content

Annofab v0.82.0 #158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 29, 2020
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
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

init:
pip install pipenv --upgrade
# blackをpipenvでなくpipでインストールする理由:
# 2020/04時点でblackはベータ版で、pipenvでblackを利用するにはPipfileに`allow_prereleases=true`を記載する必要がある。
# Pipfileに`allow_prereleases=true`を設定すると、black以外のプレリリース版(ベータ版)もインストールされてしまうが、これは避けたいのでblackはpipでインストールする
pip install black --upgrade
pipenv install --dev

format:
pipenv run autoflake --in-place --remove-all-unused-imports --ignore-init-module-imports --recursive annofabapi tests
# balckは正式版がリリースされるまでは、pipenv上で実行しない。事前にpipでblackをインストールすること。
pipenv run isort --verbose --recursive annofabapi tests
pipenv run yapf --verbose --in-place --recursive annofabapi tests
black annofabapi tests

lint:
pipenv run mypy annofabapi --config-file setup.cfg
Expand Down
4 changes: 0 additions & 4 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ pytest = "*"
pytest-xdist = "*"
pytest-cov = "*"
isort = "*"
yapf = "*"
mypy = "*"
flake8 = "*"
pylint = "*"
Expand All @@ -23,6 +22,3 @@ twine = "*"
sphinx = "==1.8.5"
autoflake = "*"
docutils = "*"

[pipenv]
allow_prereleases = true
193 changes: 95 additions & 98 deletions Pipfile.lock

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions annofabapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,14 @@
from annofabapi.resource import build, build_from_netrc, build_from_env, Resource

from .__version__ import __version__

__all__ = [
"AnnofabApi",
"AnnofabApi2",
"Wrapper",
"build",
"build_from_netrc",
"build_from_env",
"Resource",
"__version__",
]
2 changes: 1 addition & 1 deletion annofabapi/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.30.3'
__version__ = "0.31.0"
88 changes: 53 additions & 35 deletions annofabapi/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import functools
import json
import logging
from typing import Any, Callable, Dict, List, Optional, Tuple, Union # pylint: disable=unused-import
from typing import Any, Dict, Optional, Tuple

import backoff
import requests
Expand All @@ -21,6 +21,7 @@ def my_backoff(function):
"""
HTTP Status Codeが429 or 5XXのときはリトライする. 最大5分間リトライする。
"""

@functools.wraps(function)
def wrapped(*args, **kwargs):
def fatal_code(e):
Expand Down Expand Up @@ -58,8 +59,13 @@ def fatal_code(e):
# リトライする
return False

return backoff.on_exception(backoff.expo, requests.exceptions.RequestException, jitter=backoff.full_jitter,
max_time=300, giveup=fatal_code)(function)(*args, **kwargs)
return backoff.on_exception(
backoff.expo,
requests.exceptions.RequestException,
jitter=backoff.full_jitter,
max_time=300,
giveup=fatal_code,
)(function)(*args, **kwargs)

return wrapped

Expand All @@ -73,6 +79,7 @@ class AnnofabApi(AbstractAnnofabApi):
login_password: AnnoFabにログインするときのパスワード
endpoint_url: AnnoFab APIのエンドポイント。
"""

def __init__(self, login_user_id: str, login_password: str, endpoint_url: str = DEFAULT_ENDPOINT_URL):

if not login_user_id or not login_password:
Expand All @@ -95,18 +102,23 @@ class __MyToken(AuthBase):
requestsモジュールのauthに渡す情報。
http://docs.python-requests.org/en/master/user/advanced/#custom-authentication
"""

def __init__(self, id_token: str):
self.id_token = id_token

def __call__(self, req):
req.headers['Authorization'] = self.id_token
req.headers["Authorization"] = self.id_token
return req

#########################################
# Private Method
#########################################
def _create_kwargs(self, params: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, Any]] = None,
request_body: Optional[Any] = None) -> Dict[str, Any]:
def _create_kwargs(
self,
params: Optional[Dict[str, Any]] = None,
headers: Optional[Dict[str, Any]] = None,
request_body: Optional[Any] = None,
) -> Dict[str, Any]:
"""
requestsモジュールのget,...メソッドに渡すkwargsを生成する。

Expand All @@ -129,21 +141,21 @@ def _create_kwargs(self, params: Optional[Dict[str, Any]] = None, headers: Optio
new_params[key] = value

kwargs: Dict[str, Any] = {
'params': new_params,
'headers': headers,
"params": new_params,
"headers": headers,
}
if self.token_dict is not None:
kwargs.update({'auth': self.__MyToken(self.token_dict['id_token'])})
kwargs.update({"auth": self.__MyToken(self.token_dict["id_token"])})

if request_body is not None:
if isinstance(request_body, (dict, list)):
kwargs.update({'json': request_body})
kwargs.update({"json": request_body})

elif isinstance(request_body, str):
kwargs.update({'data': request_body.encode("utf-8")})
kwargs.update({"data": request_body.encode("utf-8")})

else:
kwargs.update({'data': request_body})
kwargs.update({"data": request_body})

return kwargs

Expand All @@ -160,15 +172,15 @@ def _response_to_content(response: requests.Response) -> Any:

"""

content_type = response.headers['Content-Type']
content_type = response.headers["Content-Type"]
# `Content-Type: application/json;charset=utf-8`などcharsetが含まれている場合にも対応できるようにする。
tokens = content_type.split(';')
tokens = content_type.split(";")
media_type = tokens[0].strip()

if media_type == 'application/json':
if media_type == "application/json":
content = response.json() if len(response.content) != 0 else {}

elif media_type.find('text/') >= 0:
elif media_type.find("text/") >= 0:
content = response.text

else:
Expand All @@ -177,9 +189,14 @@ def _response_to_content(response: requests.Response) -> Any:
return content

@my_backoff
def _request_wrapper(self, http_method: str, url_path: str, query_params: Optional[Dict[str, Any]] = None,
header_params: Optional[Dict[str, Any]] = None,
request_body: Optional[Any] = None) -> Tuple[Any, requests.Response]:
def _request_wrapper(
self,
http_method: str,
url_path: str,
query_params: Optional[Dict[str, Any]] = None,
header_params: Optional[Dict[str, Any]] = None,
request_body: Optional[Any] = None,
) -> Tuple[Any, requests.Response]:
"""
HTTP Requestを投げて、Reponseを返す。

Expand All @@ -198,7 +215,7 @@ def _request_wrapper(self, http_method: str, url_path: str, query_params: Option
if url_path.startswith("/labor-control") or url_path.startswith("/internal/"):
url = f"{self.endpoint_url}/api{url_path}"
else:
url = f'{self.url_prefix}{url_path}'
url = f"{self.url_prefix}{url_path}"

kwargs = self._create_kwargs(query_params, header_params, request_body)

Expand All @@ -212,7 +229,7 @@ def _request_wrapper(self, http_method: str, url_path: str, query_params: Option

_log_error_response(logger, response)

response.encoding = 'utf-8'
response.encoding = "utf-8"
_raise_for_status(response)

content = self._response_to_content(response)
Expand All @@ -230,8 +247,8 @@ def _get_signed_cookie(self, project_id) -> Tuple[Dict[str, Any], requests.Respo
Tuple[Content, Response)

"""
url_path = f'/internal/projects/{project_id}/sign-headers'
http_method = 'GET'
url_path = f"/internal/projects/{project_id}/sign-headers"
http_method = "GET"
keyword_params: Dict[str, Any] = {}
return self._request_wrapper(http_method, url_path, **keyword_params)

Expand All @@ -247,6 +264,7 @@ def _request_get_with_cookie(self, project_id: str, url: str) -> requests.Respon
Response

"""

def request(cookies):
kwargs = {"cookies": cookies}
return self.session.get(url, **kwargs)
Expand Down Expand Up @@ -282,7 +300,7 @@ def login(self) -> Tuple[Dict[str, Any], requests.Response]:
Tuple[Token, requests.Response]

"""
login_info = {'user_id': self.login_user_id, 'password': self.login_password}
login_info = {"user_id": self.login_user_id, "password": self.login_password}

url = f"{self.url_prefix}/login"
response = self.session.post(url, json=login_info)
Expand Down Expand Up @@ -313,7 +331,7 @@ def logout(self) -> Optional[Tuple[Dict[str, Any], requests.Response]]:
return None

request_body = self.token_dict
content, response = self._request_wrapper('POST', '/logout', request_body=request_body)
content, response = self._request_wrapper("POST", "/logout", request_body=request_body)
self.token_dict = None
return content, response

Expand All @@ -332,8 +350,8 @@ def refresh_token(self) -> Optional[Tuple[Dict[str, Any], requests.Response]]:
logger.info("You are not logged in.")
return None

request_body = {'refresh_token': self.token_dict['refresh_token']}
content, response = self._request_wrapper('POST', '/refresh-token', request_body=request_body)
request_body = {"refresh_token": self.token_dict["refresh_token"]}
content, response = self._request_wrapper("POST", "/refresh-token", request_body=request_body)
self.token_dict = content
return content, response

Expand All @@ -353,10 +371,10 @@ def get_labor_control(self, query_params: Optional[Dict[str, Any]] = None) -> Tu


"""
url_path = f'/labor-control'
http_method = 'GET'
url_path = f"/labor-control"
http_method = "GET"
keyword_params: Dict[str, Any] = {
'query_params': query_params,
"query_params": query_params,
}
return self._request_wrapper(http_method, url_path, **keyword_params)

Expand All @@ -372,10 +390,10 @@ def put_labor_control(self, request_body: Dict[str, Any]) -> Tuple[Any, requests


"""
url_path = f'/labor-control'
http_method = 'PUT'
url_path = f"/labor-control"
http_method = "PUT"
keyword_params: Dict[str, Any] = {
'request_body': request_body,
"request_body": request_body,
}
return self._request_wrapper(http_method, url_path, **keyword_params)

Expand All @@ -391,7 +409,7 @@ def delete_labor_control(self, data_id: str) -> Tuple[Any, requests.Response]:


"""
url_path = f'/labor-control/{data_id}'
http_method = 'DELETE'
url_path = f"/labor-control/{data_id}"
http_method = "DELETE"
keyword_params: Dict[str, Any] = {}
return self._request_wrapper(http_method, url_path, **keyword_params)
24 changes: 15 additions & 9 deletions annofabapi/api2.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from typing import Any, Callable, Dict, List, Optional, Tuple, Union # pylint: disable=unused-import
from typing import Any, Dict, Optional, Tuple

import requests
from requests.cookies import RequestsCookieJar
Expand All @@ -23,6 +23,7 @@ class AnnofabApi2(AbstractAnnofabApi2):
api: API v1のインスタンス(一部のAPIは、v1のログインメソッドを利用するため)

"""

def __init__(self, api: AnnofabApi):
self.api = api
self.url_prefix = f"{api.endpoint_url}/api/v2"
Expand All @@ -35,9 +36,14 @@ def __init__(self, api: AnnofabApi):
#########################################

@annofabapi.api.my_backoff
def _request_wrapper(self, http_method: str, url_path: str, query_params: Optional[Dict[str, Any]] = None,
header_params: Optional[Dict[str, Any]] = None,
request_body: Optional[Any] = None) -> Tuple[Any, requests.Response]:
def _request_wrapper(
self,
http_method: str,
url_path: str,
query_params: Optional[Dict[str, Any]] = None,
header_params: Optional[Dict[str, Any]] = None,
request_body: Optional[Any] = None,
) -> Tuple[Any, requests.Response]:
"""
HTTP Requestを投げて、Reponseを返す。
Args:
Expand All @@ -53,7 +59,7 @@ def _request_wrapper(self, http_method: str, url_path: str, query_params: Option

"""

url = f'{self.url_prefix}{url_path}'
url = f"{self.url_prefix}{url_path}"
kwargs = self.api._create_kwargs(query_params, header_params)

if url_path == "/sign-url":
Expand All @@ -79,7 +85,7 @@ def _request_wrapper(self, http_method: str, url_path: str, query_params: Option

_log_error_response(logger, response)

response.encoding = 'utf-8'
response.encoding = "utf-8"
_raise_for_status(response)

content = self.api._response_to_content(response)
Expand All @@ -105,10 +111,10 @@ def get_signed_access_v2(self, query_params: Dict[str, Any]) -> Tuple[Dict[str,

"""

url_path = f'/sign-url'
http_method = 'GET'
url_path = f"/sign-url"
http_method = "GET"
keyword_params: Dict[str, Any] = {
'query_params': query_params,
"query_params": query_params,
}

content, response = self._request_wrapper(http_method, url_path, **keyword_params)
Expand Down
Loading