Skip to content

AnnoFab WebAPIのエンドポイントを設定可能にする #110

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 6 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
12 changes: 8 additions & 4 deletions annofabapi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

logger = logging.getLogger(__name__)

DEFAULT_ENDPOINT_URL = "https://annofab.com/api"
"""AnnoFab WebAPIのデフォルトのエンドポイントURL"""


def my_backoff(function):
"""
Expand Down Expand Up @@ -68,20 +71,21 @@ class AnnofabApi(AbstractAnnofabApi):
Args:
login_user_id: AnnoFabにログインするときのユーザID
login_password: AnnoFabにログインするときのパスワード

endpoint_url: AnnoFab APIのエンドポイント。
"""
def __init__(self, login_user_id: str, login_password: str):
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:
raise ValueError("login_user_id or login_password is empty.")

self.login_user_id = login_user_id
self.login_password = login_password

self.endpoint_url = endpoint_url
self.URL_PREFIX = f"{endpoint_url}/v1"
Copy link
Contributor

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.

もともと定数として扱っていたので、大文字にしていました。
今回の対応で定数ではなくなったので、小文字に変更します。

self.session = requests.Session()

#: アクセスするURL
URL_PREFIX = "https://annofab.com/api/v1"
URL_PREFIX = f"{DEFAULT_ENDPOINT_URL}/v1"
Copy link
Contributor

Choose a reason for hiding this comment

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

ここにあるクラス変数の URL_PREFIX は不要じゃないでしょうか

Copy link
Collaborator Author

@yuji38kwmt yuji38kwmt Jan 22, 2020

Choose a reason for hiding this comment

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

_request_wrapperメソッドと、loginメソッドの2か所で使っているので、必要だと思いました。

def _request_wrapper(self, http_method: str, url_path: str, query_params: Optional[Dict[str, Any]] = None,

def login(self) -> Tuple[Dict[str, Any], requests.Response]:

Copy link
Contributor

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.

すみません、クラス変数とインスタンス変数を勘違いしていました…

  • クラス変数のurl_prefixは不要です。
  • インスタンス変数のself.url_prefixは、他のメソッドで使用しているので必要です。


#: login, refresh_tokenで取得したtoken情報
token_dict: Optional[Dict[str, Any]] = None
Expand Down
6 changes: 3 additions & 3 deletions annofabapi/api2.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import requests

import annofabapi.utils
from annofabapi.api import AnnofabApi
from annofabapi.api import DEFAULT_ENDPOINT_URL, AnnofabApi
from annofabapi.generated_api2 import AbstractAnnofabApi2

logger = logging.getLogger(__name__)
Expand All @@ -22,11 +22,11 @@ class AnnofabApi2(AbstractAnnofabApi2):

"""
def __init__(self, api: AnnofabApi):

self.api = api
self.URL_PREFIX = f"{api.endpoint_url}/v2"

#: アクセスするURL
URL_PREFIX = "https://annofab.com/api/v2"
URL_PREFIX = f"{DEFAULT_ENDPOINT_URL}/v2"

#: Signed Cookie情報
cookies: Optional[Dict[str, Any]] = None
Expand Down
34 changes: 23 additions & 11 deletions annofabapi/resource.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import logging
import netrc
import os
from urllib.parse import urlparse

from annofabapi import AnnofabApi, AnnofabApi2, Wrapper
from annofabapi.api import DEFAULT_ENDPOINT_URL
from annofabapi.exceptions import AnnofabApiException

logger = logging.getLogger(__name__)
Expand All @@ -15,11 +17,12 @@ class Resource:
Args:
login_user_id: AnnoFabにログインするときのユーザID
login_password: AnnoFabにログインするときのパスワード
endpoint_url: AnnoFab APIのエンドポイント。

"""
def __init__(self, login_user_id: str, login_password: str):
def __init__(self, login_user_id: str, login_password: str, endpoint_url: str = DEFAULT_ENDPOINT_URL):
#: AnnofabApi Instance
self.api = AnnofabApi(login_user_id, login_password)
self.api = AnnofabApi(login_user_id=login_user_id, login_password=login_password, endpoint_url=endpoint_url)

#: Wrapper Instance
self.wrapper = Wrapper(self.api)
Expand All @@ -28,25 +31,29 @@ def __init__(self, login_user_id: str, login_password: str):
self.api2 = AnnofabApi2(self.api)


def build(login_user_id: str, login_password: str) -> Resource:
def build(login_user_id: str, login_password: str, endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
"""
AnnofabApi, Wrapperのインスタンスを保持するインスタンスを生成する。

Args:
login_user_id: AnnoFabにログインするときのユーザID
login_password: AnnoFabにログインするときのパスワード
endpoint_url: AnnoFab APIのエンドポイント。

Returns:
AnnofabApi, Wrapperのインスタンスを保持するインスタンス

"""
return Resource(login_user_id, login_password)
return Resource(login_user_id, login_password, endpoint_url=endpoint_url)


def build_from_netrc() -> Resource:
def build_from_netrc(endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
"""
``.netrc`` ファイルから、annnofabapi.Resourceインスタンスを生成する。

Args:
endpoint_url: AnnoFab APIのエンドポイント。

Returns:
annnofabapi.Resourceインスタンス

Expand All @@ -56,23 +63,28 @@ def build_from_netrc() -> Resource:
except FileNotFoundError as e:
raise AnnofabApiException(e)

if 'annofab.com' not in netrc_hosts:
raise AnnofabApiException("The `.netrc` file does not contain the machine name `annofab.com`")
annofab_hostname = (urlparse(endpoint_url)).hostname

if annofab_hostname not in netrc_hosts:
raise AnnofabApiException(f"The `.netrc` file does not contain the machine name '{annofab_hostname}'")

host = netrc_hosts['annofab.com']
host = netrc_hosts[annofab_hostname]
login_user_id = host[0]
login_password = host[2]
if login_user_id is None or login_password is None:
raise AnnofabApiException("User ID or password in the .netrc file are None.")

logger.debug(".netrcファイルからAnnoFab認証情報を読み込んだ。")
return Resource(login_user_id, login_password)
return Resource(login_user_id, login_password, endpoint_url=endpoint_url)


def build_from_env() -> Resource:
def build_from_env(endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
"""
環境変数 ``ANNOFAB_USER_ID`` , ``ANNOFAB_PASSWORD`` から、annnofabapi.Resourceインスタンスを生成する。

Args:
endpoint_url: AnnoFab APIのエンドポイント。

Returns:
annnofabapi.Resourceインスタンス

Expand All @@ -83,4 +95,4 @@ def build_from_env() -> Resource:
raise AnnofabApiException("`ANNOFAB_USER_ID` or `ANNOFAB_PASSWORD` environment variable are empty.")

logger.debug("環境変数からAnnoFab認証情報を読み込んだ。")
return Resource(login_user_id, login_password)
return Resource(login_user_id, login_password, endpoint_url=endpoint_url)
39 changes: 24 additions & 15 deletions tests/test_local_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,27 @@
os.chdir(os.path.dirname(os.path.abspath(__file__)) + "/../")


def test_build():
# ".netrc"ファイルが存在すること前提
assert isinstance(annofabapi.build_from_netrc(), annofabapi.Resource)

with pytest.raises(ValueError):
annofabapi.AnnofabApi("test_user", "")

with pytest.raises(annofabapi.exceptions.AnnofabApiException):
os.environ.pop('ANNOFAB_USER_ID', None)
os.environ.pop('ANNOFAB_PASSWORD', None)
annofabapi.build_from_env()

os.environ['ANNOFAB_USER_ID'] = 'FOO'
os.environ['ANNOFAB_PASSWORD'] = 'BAR'
assert isinstance(annofabapi.build_from_env(), annofabapi.Resource)
class TestBuild:
def test_build_from_netrc(self):
# ".netrc"ファイルが存在すること前提
assert isinstance(annofabapi.build_from_netrc(), annofabapi.Resource)

def test_raise_ValueError(self):
with pytest.raises(ValueError):
annofabapi.AnnofabApi("test_user", "")

def test_build_from_env_raise_AnnofabApiException(self):
with pytest.raises(annofabapi.exceptions.AnnofabApiException):
os.environ.pop('ANNOFAB_USER_ID', None)
os.environ.pop('ANNOFAB_PASSWORD', None)
annofabapi.build_from_env()

def test_build_from_env(self):
os.environ['ANNOFAB_USER_ID'] = 'FOO'
os.environ['ANNOFAB_PASSWORD'] = 'BAR'
assert isinstance(annofabapi.build_from_env(), annofabapi.Resource)

def test_build_with_endpoint(self):
resource = annofabapi.build("test_user", "password", "https://localhost:8080")
assert resource.api.URL_PREFIX == "https://localhost:8080/v1"
assert resource.api2.URL_PREFIX == "https://localhost:8080/v2"