From 138aaf94bfbc9c5cabd59b4fcf89148edf764ddf Mon Sep 17 00:00:00 2001 From: Chihiro Hio Date: Thu, 21 Dec 2023 16:37:56 +0900 Subject: [PATCH 1/6] feat: add APIAuthError and detailed error message --- alpaca/broker/client.py | 4 ++- alpaca/common/exceptions.py | 59 ++++++++++++++++++++++++++++++++++++- alpaca/common/rest.py | 5 +++- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/alpaca/broker/client.py b/alpaca/broker/client.py index 70bd986f..6dc65f29 100644 --- a/alpaca/broker/client.py +++ b/alpaca/broker/client.py @@ -41,7 +41,7 @@ UpdateAccountRequest, GetEventsRequest, ) -from alpaca.common.exceptions import APIError +from alpaca.common.exceptions import APIError, APIAuthError from alpaca.common.constants import ( ACCOUNT_ACTIVITIES_DEFAULT_PAGE_SIZE, BROKER_DOCUMENT_UPLOAD_LIMIT, @@ -663,6 +663,8 @@ def download_trade_document_for_account_by_id( continue if "code" in response.text: error = response.json() + if response.status_code == 401: + raise APIAuthError(error, http_error) if "code" in error: raise APIError(error, http_error) else: diff --git a/alpaca/common/exceptions.py b/alpaca/common/exceptions.py index 613bdae3..092e0895 100644 --- a/alpaca/common/exceptions.py +++ b/alpaca/common/exceptions.py @@ -8,9 +8,66 @@ class APIError(Exception): """ def __init__(self, error, http_error=None): - super().__init__(error) + detailed_error = { + "message": error, + } + + if http_error is not None: + if hasattr(http_error, "response"): + detailed_error["status_code"] = http_error.response.status_code + detailed_error["reason"] = http_error.response.reason + if hasattr(http_error, "request"): + detailed_error["method"] = http_error.request.method + detailed_error["url"] = http_error.request.url + + self._error = error + self._http_error = http_error + super().__init__(detailed_error) + + @property + def code(self): + error = json.loads(self._error) + return error["code"] + + @property + def status_code(self): + http_error = self._http_error + if http_error is not None and hasattr(http_error, "response"): + return http_error.response.status_code + + @property + def request(self): + if self._http_error is not None: + return self._http_error.request + + @property + def response(self): + if self._http_error is not None: + return self._http_error.response + + +class APIAuthError(Exception): + """ + Represent API Auth related error. + """ + + def __init__(self, error, http_error=None): + detailed_error = { + "message": error, + "tips": "please check your API key and environment (paper/sandbox/live)." + } + + if http_error is not None: + if hasattr(http_error, "response"): + detailed_error["status_code"] = http_error.response.status_code + detailed_error["reason"] = http_error.response.reason + if hasattr(http_error, "request"): + detailed_error["method"] = http_error.request.method + detailed_error["url"] = http_error.request.url + self._error = error self._http_error = http_error + super().__init__(detailed_error) @property def code(self): diff --git a/alpaca/common/rest.py b/alpaca/common/rest.py index adbc5660..85cafaf2 100644 --- a/alpaca/common/rest.py +++ b/alpaca/common/rest.py @@ -15,7 +15,7 @@ ) from alpaca import __version__ -from alpaca.common.exceptions import APIError, RetryException +from alpaca.common.exceptions import APIError, APIAuthError, RetryException from alpaca.common.types import RawData, HTTPResult, Credentials from .constants import PageItem from .enums import PaginationType, BaseURL @@ -202,6 +202,9 @@ def _one_request(self, method: str, url: str, opts: dict, retry: int) -> dict: # raise API error for all other errors error = response.text + if response.status_code == "401": + raise APIAuthError(error, http_error) + raise APIError(error, http_error) if response.text != "": From 9a2a65e3dcde82d6b675b7fa4ffe0e8cf6c8adcd Mon Sep 17 00:00:00 2001 From: Chihiro Hio Date: Thu, 21 Dec 2023 16:41:44 +0900 Subject: [PATCH 2/6] fix: type of status_code to number instead of str --- alpaca/common/rest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alpaca/common/rest.py b/alpaca/common/rest.py index 85cafaf2..ced9c80e 100644 --- a/alpaca/common/rest.py +++ b/alpaca/common/rest.py @@ -202,7 +202,7 @@ def _one_request(self, method: str, url: str, opts: dict, retry: int) -> dict: # raise API error for all other errors error = response.text - if response.status_code == "401": + if response.status_code == 401: raise APIAuthError(error, http_error) raise APIError(error, http_error) From c808f9760cc788f53dc1413edcc5acd20ee1d31e Mon Sep 17 00:00:00 2001 From: Chihiro Hio Date: Thu, 21 Dec 2023 16:48:15 +0900 Subject: [PATCH 3/6] feat: use APIError instead of APIAuthError --- alpaca/broker/client.py | 4 +--- alpaca/common/exceptions.py | 4 +++- alpaca/common/rest.py | 5 +---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/alpaca/broker/client.py b/alpaca/broker/client.py index 6dc65f29..70bd986f 100644 --- a/alpaca/broker/client.py +++ b/alpaca/broker/client.py @@ -41,7 +41,7 @@ UpdateAccountRequest, GetEventsRequest, ) -from alpaca.common.exceptions import APIError, APIAuthError +from alpaca.common.exceptions import APIError from alpaca.common.constants import ( ACCOUNT_ACTIVITIES_DEFAULT_PAGE_SIZE, BROKER_DOCUMENT_UPLOAD_LIMIT, @@ -663,8 +663,6 @@ def download_trade_document_for_account_by_id( continue if "code" in response.text: error = response.json() - if response.status_code == 401: - raise APIAuthError(error, http_error) if "code" in error: raise APIError(error, http_error) else: diff --git a/alpaca/common/exceptions.py b/alpaca/common/exceptions.py index 092e0895..38322151 100644 --- a/alpaca/common/exceptions.py +++ b/alpaca/common/exceptions.py @@ -9,7 +9,7 @@ class APIError(Exception): def __init__(self, error, http_error=None): detailed_error = { - "message": error, + "payload": error, } if http_error is not None: @@ -19,6 +19,8 @@ def __init__(self, error, http_error=None): if hasattr(http_error, "request"): detailed_error["method"] = http_error.request.method detailed_error["url"] = http_error.request.url + if detailed_error["status_code"] == 401: + detailed_error["tips"] = "please check your API key and environment (paper/sandbox/live)" self._error = error self._http_error = http_error diff --git a/alpaca/common/rest.py b/alpaca/common/rest.py index ced9c80e..adbc5660 100644 --- a/alpaca/common/rest.py +++ b/alpaca/common/rest.py @@ -15,7 +15,7 @@ ) from alpaca import __version__ -from alpaca.common.exceptions import APIError, APIAuthError, RetryException +from alpaca.common.exceptions import APIError, RetryException from alpaca.common.types import RawData, HTTPResult, Credentials from .constants import PageItem from .enums import PaginationType, BaseURL @@ -202,9 +202,6 @@ def _one_request(self, method: str, url: str, opts: dict, retry: int) -> dict: # raise API error for all other errors error = response.text - if response.status_code == 401: - raise APIAuthError(error, http_error) - raise APIError(error, http_error) if response.text != "": From f1a4f18ab8a6fbed89eaf9b9350cb1a55becace6 Mon Sep 17 00:00:00 2001 From: Chihiro Hio Date: Thu, 21 Dec 2023 16:54:46 +0900 Subject: [PATCH 4/6] feat: add tips for http status code 403 --- alpaca/common/exceptions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/alpaca/common/exceptions.py b/alpaca/common/exceptions.py index 38322151..a95bf3ae 100644 --- a/alpaca/common/exceptions.py +++ b/alpaca/common/exceptions.py @@ -19,7 +19,8 @@ def __init__(self, error, http_error=None): if hasattr(http_error, "request"): detailed_error["method"] = http_error.request.method detailed_error["url"] = http_error.request.url - if detailed_error["status_code"] == 401: + # add tips for auth key error + if detailed_error["status_code"] in [401, 403]: detailed_error["tips"] = "please check your API key and environment (paper/sandbox/live)" self._error = error From eb86f4abe1dd44c924a16e7e4cbae514d6aaf1e4 Mon Sep 17 00:00:00 2001 From: Chihiro Hio Date: Thu, 21 Dec 2023 17:35:38 +0900 Subject: [PATCH 5/6] fix: black and remove APIAuthError --- alpaca/common/exceptions.py | 49 +++---------------------------------- 1 file changed, 3 insertions(+), 46 deletions(-) diff --git a/alpaca/common/exceptions.py b/alpaca/common/exceptions.py index a95bf3ae..1e928056 100644 --- a/alpaca/common/exceptions.py +++ b/alpaca/common/exceptions.py @@ -21,52 +21,9 @@ def __init__(self, error, http_error=None): detailed_error["url"] = http_error.request.url # add tips for auth key error if detailed_error["status_code"] in [401, 403]: - detailed_error["tips"] = "please check your API key and environment (paper/sandbox/live)" - - self._error = error - self._http_error = http_error - super().__init__(detailed_error) - - @property - def code(self): - error = json.loads(self._error) - return error["code"] - - @property - def status_code(self): - http_error = self._http_error - if http_error is not None and hasattr(http_error, "response"): - return http_error.response.status_code - - @property - def request(self): - if self._http_error is not None: - return self._http_error.request - - @property - def response(self): - if self._http_error is not None: - return self._http_error.response - - -class APIAuthError(Exception): - """ - Represent API Auth related error. - """ - - def __init__(self, error, http_error=None): - detailed_error = { - "message": error, - "tips": "please check your API key and environment (paper/sandbox/live)." - } - - if http_error is not None: - if hasattr(http_error, "response"): - detailed_error["status_code"] = http_error.response.status_code - detailed_error["reason"] = http_error.response.reason - if hasattr(http_error, "request"): - detailed_error["method"] = http_error.request.method - detailed_error["url"] = http_error.request.url + detailed_error[ + "tips" + ] = "please check your API key and environment (paper/sandbox/live)" self._error = error self._http_error = http_error From b7f027f12d1c4876835a5352241a3825730a5688 Mon Sep 17 00:00:00 2001 From: Chihiro Hio Date: Tue, 26 Dec 2023 10:26:08 +0900 Subject: [PATCH 6/6] fix: limit tips message only for http status code 401 --- alpaca/common/exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alpaca/common/exceptions.py b/alpaca/common/exceptions.py index 1e928056..298acdec 100644 --- a/alpaca/common/exceptions.py +++ b/alpaca/common/exceptions.py @@ -20,7 +20,7 @@ def __init__(self, error, http_error=None): detailed_error["method"] = http_error.request.method detailed_error["url"] = http_error.request.url # add tips for auth key error - if detailed_error["status_code"] in [401, 403]: + if detailed_error["status_code"] == 401: detailed_error[ "tips" ] = "please check your API key and environment (paper/sandbox/live)"