Skip to content

Commit

Permalink
Merge pull request #60 from kurusugawa-computer/update-pip-
Browse files Browse the repository at this point in the history
`resource.build`関数の引数に`login_user_id`, `login_password`を追加する
  • Loading branch information
yuji38kwmt authored Jan 30, 2024
2 parents eefe327 + 69d01b7 commit c1a5b0b
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 22 deletions.
2 changes: 1 addition & 1 deletion annoworkapi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ class AnnoworkApi(AbstractAnnoworkApi):
endpoint_url: WebAPI URLのbase部分
"""

def __init__(self, login_user_id: str, login_password: str, endpoint_url: str = DEFAULT_ENDPOINT_URL):
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.")

Expand Down
6 changes: 6 additions & 0 deletions annoworkapi/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ class AnnoworkApiException(Exception):
"""
annoworkapi に関するException
"""


class CredentialsNotFoundError(AnnoworkApiException):
"""
Annoworkの認証情報が見つからないときのエラー
"""
48 changes: 27 additions & 21 deletions annoworkapi/resource.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import logging
import netrc
import os
from typing import Optional
from urllib.parse import urlparse

from annoworkapi.api import DEFAULT_ENDPOINT_URL, AnnoworkApi
from annoworkapi.exceptions import AnnoworkApiException
from annoworkapi.exceptions import AnnoworkApiException, CredentialsNotFoundError
from annoworkapi.wrapper import Wrapper

logger = logging.getLogger(__name__)
Expand All @@ -20,7 +21,7 @@ class Resource:
"""

def __init__(self, login_user_id: str, login_password: str, endpoint_url: str = DEFAULT_ENDPOINT_URL):
def __init__(self, login_user_id: str, login_password: str, *, endpoint_url: str = DEFAULT_ENDPOINT_URL):
self.api = AnnoworkApi(login_user_id=login_user_id, login_password=login_password, endpoint_url=endpoint_url)
self.wrapper = Wrapper(self.api)

Expand All @@ -29,7 +30,7 @@ def __init__(self, login_user_id: str, login_password: str, endpoint_url: str =
)


def build_from_netrc(endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
def build_from_netrc(*, endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
"""
``.netrc`` ファイルから、Resourceインスタンスを生成する。
"""
Expand All @@ -41,18 +42,18 @@ def build_from_netrc(endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
annowork_hostname = (urlparse(endpoint_url)).hostname

if annowork_hostname not in netrc_hosts:
raise AnnoworkApiException(f"The `.netrc` file does not contain the machine name '{annowork_hostname}'")
raise CredentialsNotFoundError(f"`.netrc`ファイルの`machine`にAnnoworkのドメイン'{annowork_hostname}'が存在しません。")

host = netrc_hosts[annowork_hostname]
login_user_id = host[0]
login_password = host[2]
if login_user_id is None or login_password is None:
raise AnnoworkApiException("User ID or password in the .netrc file are None.")
raise CredentialsNotFoundError("`.netrc`ファイルに、AnnoworkのユーザーIDまたはパスワードが記載されていません。")

return Resource(login_user_id, login_password, endpoint_url=endpoint_url)


def build_from_env(endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
def build_from_env(*, endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
"""
環境変数 ``ANNOWORK_USER_ID`` , ``ANNOWORK_PASSWORD`` から、Resourceインスタンスを生成する。
Expand All @@ -66,27 +67,32 @@ def build_from_env(endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
login_user_id = os.environ.get("ANNOWORK_USER_ID")
login_password = os.environ.get("ANNOWORK_PASSWORD")
if login_user_id is None or login_password is None:
raise AnnoworkApiException("`ANNOWORK_USER_ID` or `ANNOWORK_PASSWORD` environment variable are empty.")
raise CredentialsNotFoundError("環境変数`ANNOWORK_USER_ID``ANNOWORK_PASSWORD`のいずれかが空です。")

return Resource(login_user_id, login_password, endpoint_url=endpoint_url)


def build(endpoint_url: str = DEFAULT_ENDPOINT_URL) -> Resource:
def build(
*,
login_user_id: Optional[str] = None,
login_password: Optional[str] = None,
endpoint_url: str = DEFAULT_ENDPOINT_URL,
) -> Resource:
"""
``.netrc`` ファイルまたは環境変数から認証情報を取得し、Resourceインスタンスを生成します。
netrc, 環境変数の順に認証情報を読み込みます。
"""
# '.netrc'ファイルから認証情報を取得する
try:
return build_from_netrc(endpoint_url)
except AnnoworkApiException:
pass

# 環境変数から認証情報を取得する
try:
return build_from_env(endpoint_url)
except AnnoworkApiException:
pass

raise AnnoworkApiException("`.netrc`ファイルまたは環境変数にAnnowork認証情報はありませんでした。")
if login_user_id is not None and login_password is not None:
return Resource(login_user_id, login_password, endpoint_url=endpoint_url)

elif login_user_id is None and login_password is None:
try:
return build_from_env(endpoint_url=endpoint_url)
except CredentialsNotFoundError:
try:
return build_from_netrc(endpoint_url=endpoint_url)
except CredentialsNotFoundError as e:
raise CredentialsNotFoundError("環境変数または`.netrc`ファイルにAnnowork認証情報はありませんでした。") from e
else:
raise ValueError("引数`login_user_id`か`login_password`のどちらか一方がNoneです。両方Noneでないか、両方Noneである必要があります。")
51 changes: 51 additions & 0 deletions tests/test_resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
resource.pyのテストコード
"""
import os

import pytest

from annoworkapi.exceptions import CredentialsNotFoundError
from annoworkapi.resource import Resource, build, build_from_env

# プロジェクトトップに移動する
os.chdir(os.path.dirname(os.path.abspath(__file__)) + "/../")


class Test__build_from_env:
def test_環境変数の認証情報を元にインスタンスが作成される(self):
os.environ["ANNOWORK_USER_ID"] = "FOO"
os.environ["ANNOWORK_PASSWORD"] = "BAR"
actual = build_from_env()
assert isinstance(actual, Resource)

def test_環境変数に認証情報がない場合はCredentialsNotFoundErrorが発生する(self):
os.environ.pop("ANNOWORK_USER_ID", None)
os.environ.pop("ANNOWORK_PASSWORD", None)
with pytest.raises(CredentialsNotFoundError):
build_from_env()


# `.netrc`ファイルを事前に準備するのが難しいので、テストしない
# class Test__build_from_netrc:
# pass


class Test__build:
def test_引数に認証情報を指定する(self):
actual = build(login_user_id="FOO", login_password="BAR")
assert isinstance(actual, Resource)

def test_引数にユーザーIDのみ指定するとValueErrorが発生する(self):
with pytest.raises(ValueError):
build(login_user_id="FOO")

def test_引数にパスワードのみ指定するとValueErrorが発生する(self):
with pytest.raises(ValueError):
build(login_password="FOO")

def test_引数に認証情報を指定しないと環境変数から認証情報を読み込む(self):
os.environ["ANNOWORK_USER_ID"] = "FOO"
os.environ["ANNOWORK_PASSWORD"] = "BAR"
actual = build()
assert isinstance(actual, Resource)

0 comments on commit c1a5b0b

Please sign in to comment.