Skip to content

Commit 01c3eb1

Browse files
committed
0.5.0: Do not handle relogin internally, let the user code decide what to do
1 parent a6b62fe commit 01c3eb1

File tree

8 files changed

+183
-179
lines changed

8 files changed

+183
-179
lines changed

poetry.lock

Lines changed: 163 additions & 138 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[tool.poetry]
22
name = "saic_ismart_client_ng"
33
homepage = "https://github.com/SAIC-iSmart-API/saic-python-client-ng"
4-
version = "0.3.0"
4+
version = "0.4.0"
55
description = "SAIC next gen client library (MG iSMART)"
66
authors = [
77
"Giovanni Condello <[email protected]>",
@@ -22,17 +22,17 @@ classifiers = [
2222
python = "^3.11"
2323
pycryptodome = "^3.20.0"
2424
httpx = "^0.27.0"
25-
tenacity = "^8.2.3"
25+
tenacity = "^9.0.0"
2626
dacite = "^1.8.1"
2727

2828

2929
[tool.poetry.dev-dependencies]
3030
pytest = "^8.2.2"
3131
mock = "^5.1.0"
3232
coverage = "^7.5.4"
33-
ruff = "^0.4.10"
33+
ruff = "^0.6.0"
3434
pytest-cov = "^5.0.0"
35-
pytest-asyncio = "^0.23.7"
35+
pytest-asyncio = "^0.24.0"
3636
pytest-mock = "^3.14.0"
3737

3838

src/saic_ismart_client_ng/api/base.py

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import asyncio
21
import datetime
32
import json
43
import logging
@@ -31,7 +30,7 @@ def __init__(
3130
self.__configuration = configuration
3231
self.__login_client = SaicLoginClient(configuration, listener=listener)
3332
self.__api_client = SaicApiClient(configuration, listener=listener)
34-
self.__token_expiration = None
33+
self.__token_expiration: Optional[datetime.datetime] = None
3534

3635
@property
3736
def configuration(self) -> SaicApiConfiguration:
@@ -137,12 +136,9 @@ async def deserialize(
137136
error_message = json_data.get('message', 'Unknown error')
138137
logger.debug(f"Response code: {return_code} {response.text}")
139138

140-
if return_code == 401:
141-
await self._handle_logout(
142-
error_message=error_message,
143-
return_code=return_code,
144-
response=response,
145-
)
139+
if return_code in (401, 403) or response.status_code in (401, 403):
140+
self.logout()
141+
raise SaicLogoutException(response.text, return_code)
146142

147143
if return_code in (2, 3, 7):
148144
logger.error(f"API call return code is not acceptable: {return_code}: {response.text}")
@@ -197,21 +193,14 @@ async def deserialize(
197193
else:
198194
raise SaicApiException(f"Failed to deserialize response: {e}. Original json was {response.text}") from e
199195

200-
async def _handle_logout(self, *, error_message: str, return_code: int, response: httpx.Response):
201-
logger.error(f"API client got de-authenticated. {return_code}: {response.text}")
202-
self.logout()
203-
relogin_delay = self.__configuration.relogin_delay
204-
if relogin_delay:
205-
logger.warning(f"Waiting {relogin_delay}s since we got logged out.")
206-
await asyncio.sleep(relogin_delay)
207-
logger.warning("Logging in since we got logged out")
208-
await self.login()
209-
raise SaicApiException(error_message, return_code=return_code)
210-
211196
def logout(self):
212197
self.api_client.user_token = None
213198
self.__token_expiration = None
214199

200+
def is_logged_in(self) -> bool:
201+
return self.__token_expiration is not None \
202+
and self.__token_expiration > datetime.datetime.now()
203+
215204

216205
def saic_api_after_retry(retry_state):
217206
wrapped_exception = retry_state.outcome.exception()
@@ -231,10 +220,10 @@ def saic_api_retry_policy(retry_state):
231220
logger.debug("Retrying since we got SaicApiRetryException")
232221
return True
233222
elif isinstance(wrapped_exception, SaicLogoutException):
234-
logger.error("Retrying since we got logged out")
235-
return True
223+
logger.error("Not retrying since we got logged out")
224+
return False
236225
elif isinstance(wrapped_exception, SaicApiException):
237-
logger.error("NOT Retrying since we got a generic exception")
226+
logger.error("Not retrying since we got a generic exception")
238227
return False
239228
else:
240229
logger.error(f"Not retrying {retry_state.args} {wrapped_exception}")

src/saic_ismart_client_ng/model.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ def __init__(
88
base_uri: str = "https://gateway-mg-eu.soimt.com/api.app/v1/",
99
tenant_id: str = "459771",
1010
region: str = "eu",
11-
relogin_delay: float = None,
1211
sms_delivery_delay: float = 3.0,
1312
):
1413
self.__username = username
@@ -18,7 +17,6 @@ def __init__(
1817
self.__base_uri = base_uri
1918
self.__tenant_id = tenant_id
2019
self.__region = region
21-
self.__relogin_delay = relogin_delay
2220
self.__sms_delivery_delay = sms_delivery_delay
2321

2422
@property
@@ -49,10 +47,6 @@ def tenant_id(self):
4947
def region(self):
5048
return self.__region
5149

52-
@property
53-
def relogin_delay(self):
54-
return self.__relogin_delay
55-
5650
@property
5751
def sms_delivery_delay(self):
5852
return self.__sms_delivery_delay

src/saic_ismart_client_ng/net/client/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import httpx
44

5-
from saic_ismart_client_ng.exceptions import SaicApiException
5+
from saic_ismart_client_ng.exceptions import SaicLogoutException
66
from saic_ismart_client_ng.listener import SaicApiListener
77
from saic_ismart_client_ng.model import SaicApiConfiguration
88
from saic_ismart_client_ng.net.client import AbstractSaicClient
@@ -20,5 +20,5 @@ def __init__(
2020

2121
async def encrypt_request(self, modified_request: httpx.Request):
2222
if not self.user_token:
23-
raise SaicApiException("Client not authenticated, please call login first")
23+
raise SaicLogoutException("Client not authenticated, please call login first", return_code=401)
2424
await super().encrypt_request(modified_request)

src/saic_ismart_client_ng/net/crypto.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def encrypt_response(
150150
response_timestamp_ms: int,
151151
base_uri: str,
152152
tenant_id: str,
153-
user_token: '',
153+
user_token: str = '',
154154
):
155155
request_content = ""
156156
request_path = str(original_request_url).replace(base_uri, "/")

tests/security_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ async def test_a_request_should_encrypt_properly():
5050

5151
await encrypt_httpx_request(modified_request=original_request, request_timestamp=ts, base_uri=base_uri,
5252
region=region, tenant_id=tenant_id)
53-
assert original_request != None
53+
assert original_request is not None
5454
assert region == original_request.headers['REGION']
5555
assert tenant_id == original_request.headers['tenant-id']
5656
assert 'app' == original_request.headers['User-Type']
@@ -78,7 +78,7 @@ async def test_a_request_should_decrypt_properly():
7878
region=region, tenant_id=tenant_id)
7979
decrypted = await decrypt_httpx_request(original_request, base_uri=base_uri)
8080

81-
assert decrypted != None
81+
assert decrypted is not None
8282
decrypted_json = json.loads(decrypted)
8383
assert expected_json == decrypted_json
8484

tests/test_model.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ def setUp(self):
1212
"https://test-uri.com",
1313
"123456",
1414
"test_region",
15-
10.0,
1615
5.0
1716
)
1817

@@ -37,9 +36,6 @@ def test_tenant_id(self):
3736
def test_region(self):
3837
self.assertEqual(self.config.region, "test_region")
3938

40-
def test_relogin_delay(self):
41-
self.assertEqual(self.config.relogin_delay, 10.0)
42-
4339
def test_sms_delivery_delay(self):
4440
self.assertEqual(self.config.sms_delivery_delay, 5.0)
4541

0 commit comments

Comments
 (0)