diff --git a/README.md b/README.md index 375a03e..ba37c4d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ client = iec.IecClient("123456789") try: await client.manual_login() # login with user inputs except iec.exceptions.IECError as err: - logger.error("Failed Login: (Code %d): %s", err.code, err.error) + logger.error(f"Failed Login: (Code {err.code}): {err.error}") raise customer = await client.get_customer() diff --git a/example.py b/example.py index abd2f85..7696e47 100755 --- a/example.py +++ b/example.py @@ -4,24 +4,20 @@ import concurrent.futures import os from datetime import datetime, timedelta -from logging import config, getLogger import aiohttp +from loguru import logger from iec_api.iec_client import IecClient from iec_api.login import IECLoginError from iec_api.models.exceptions import IECError -ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -config.fileConfig(ROOT_DIR + "/" + "logging.conf", disable_existing_loggers=False) -logger = getLogger(__name__) - async def main(): session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False), timeout=aiohttp.ClientTimeout(total=10)) try: # Example of usage - client = IecClient(123456789, session) + client = IecClient(200461929, session) token_json_file = "token.json" if os.path.exists(token_json_file): @@ -34,7 +30,7 @@ async def main(): await client.verify_otp(otp) await client.save_token_to_file(token_json_file) except IECLoginError as err: - logger.error("Failed Login: (Code %d): %s", err.code, err.error) + logger.error(f"Failed Login: (Code {err.code}): {err.error}") raise # refresh token example @@ -84,7 +80,7 @@ async def main(): print(await client.get_device_type()) print(await client.get_billing_invoices()) except IECError as err: - logger.error("IEC Error: (Code %d): %s", err.code, err.error) + logger.error(f"IEC Error: (Code {err.code}): {err.error}") finally: await session.close() diff --git a/iec_api/commons.py b/iec_api/commons.py index 0b9739a..303e52f 100644 --- a/iec_api/commons.py +++ b/iec_api/commons.py @@ -3,16 +3,14 @@ import re from concurrent.futures import ThreadPoolExecutor from json import JSONDecodeError -from logging import getLogger from typing import Any, Optional from aiohttp import ClientError, ClientSession +from loguru import logger from iec_api.models.exceptions import IECError from iec_api.models.response_descriptor import RESPONSE_DESCRIPTOR_FIELD, ErrorResponseDescriptor -logger = getLogger(__name__) - def add_auth_bearer_to_headers(headers: dict[str, str], token: str) -> dict[str, str]: """ @@ -27,10 +25,10 @@ def add_auth_bearer_to_headers(headers: dict[str, str], token: str) -> dict[str, return headers -PHONE_REGEX: str = "^(+972|0)5[0-9]{8}$" +PHONE_REGEX = "^(+972|0)5[0-9]{8}$" -def check_phone(phone): +def check_phone(phone: str): """ Check if the phone number is valid. Args: @@ -80,7 +78,7 @@ async def send_get_request( if not timeout: timeout = session.timeout - logger.debug("HTTP GET: %s", url) + logger.debug(f"HTTP GET: {url}") resp = await session.get(url=url, headers=headers, timeout=timeout) json_resp: dict = await resp.json(content_type=None) except TimeoutError as ex: @@ -90,7 +88,7 @@ async def send_get_request( except JSONDecodeError as ex: raise IECError(-1, f"Received invalid response from IEC API: {str(ex)}") - logger.debug("HTTP GET Response: %s", json_resp) + logger.debug(f"HTTP GET Response: {json_resp}") if resp.status != http.HTTPStatus.OK: logger.warning(f"Failed call: (Code {resp.status}): {resp.reason}") if len(json_resp) > 0 and json_resp.get(RESPONSE_DESCRIPTOR_FIELD) is not None: @@ -116,7 +114,9 @@ async def send_non_json_get_request( if not timeout: timeout = session.timeout - logger.debug("HTTP GET: %s", url) + logger.debug( + f"HTTP GET: {url}", + ) resp = await session.get(url=url, headers=headers, timeout=timeout) resp_content = await resp.text(encoding=encoding) except TimeoutError as ex: @@ -126,7 +126,7 @@ async def send_non_json_get_request( except JSONDecodeError as ex: raise IECError(-1, f"Received invalid response from IEC API: {str(ex)}") - logger.debug("HTTP GET Response: %s", resp_content) + logger.debug(f"HTTP GET Response: {resp_content}") return resp_content @@ -146,14 +146,10 @@ async def send_post_request( if not timeout: headers = session.timeout - logger.debug("HTTP POST: %s", url) - logger.debug("HTTP Content: %s", data or json_data) + logger.debug(f"HTTP POST: {url}") + logger.debug(f"HTTP Content: {data or json_data}") - if data: - resp = await session.post(url=url, data=data, headers=headers, timeout=timeout) - else: - if json_data: - resp = await session.post(url=url, json=json_data, headers=headers, timeout=timeout) + resp = await session.post(url=url, data=data, json=json_data, headers=headers, timeout=timeout) json_resp: dict = await resp.json(content_type=None) except TimeoutError as ex: @@ -163,7 +159,7 @@ async def send_post_request( except JSONDecodeError as ex: raise IECError(-1, f"Received invalid response from IEC API: {str(ex)}") - logger.debug("HTTP POST Response: %s", json_resp) + logger.debug(f"HTTP POST Response: {json_resp}") if resp.status != http.HTTPStatus.OK: logger.warning(f"Failed call: (Code {resp.status}): {resp.reason}") diff --git a/iec_api/data.py b/iec_api/data.py index 5319360..5127165 100644 --- a/iec_api/data.py +++ b/iec_api/data.py @@ -1,8 +1,8 @@ -import logging from datetime import datetime from typing import Optional, TypeVar from aiohttp import ClientSession +from loguru import logger from mashumaro.codecs import BasicDecoder from iec_api import commons @@ -40,8 +40,6 @@ from iec_api.models.remote_reading import ReadingResolution, RemoteReadingRequest, RemoteReadingResponse from iec_api.models.response_descriptor import ResponseWithDescriptor -logger = logging.getLogger(__name__) - T = TypeVar("T") @@ -82,7 +80,7 @@ async def get_customer(session: ClientSession, token: JWT) -> Optional[Customer] # sending get request and saving the response as response object response = await commons.send_get_request(session=session, url=GET_CONSUMER_URL, headers=headers) - logger.debug("Response: %s", response) + logger.debug(f"Response: {response}") return Customer.from_dict(response) @@ -106,7 +104,6 @@ async def get_remote_reading( url = GET_REQUEST_READING_URL.format(contract_id=contract_id) headers = commons.add_auth_bearer_to_headers(HEADERS_WITH_AUTH, token.id_token) - logger.debug(f"HTTP POST: {url}\nData:{req.to_dict()}") response = await commons.send_post_request(session=session, url=url, headers=headers, json_data=req.to_dict()) @@ -155,7 +152,7 @@ async def get_devices(session: ClientSession, token: JWT, contract_id: str) -> l session=session, url=GET_DEVICES_URL.format(contract_id=contract_id), headers=headers ) - logger.debug("Response: %s", response) + logger.debug(f"Response: {response}") return [Device.from_dict(device) for device in response] diff --git a/iec_api/iec_client.py b/iec_api/iec_client.py index a26c888..e3c3a44 100644 --- a/iec_api/iec_client.py +++ b/iec_api/iec_client.py @@ -1,12 +1,12 @@ import asyncio import atexit import datetime -from logging import getLogger from typing import Optional import aiohttp import jwt from aiohttp import ClientSession +from loguru import logger from iec_api import data, login from iec_api.commons import is_valid_israeli_id @@ -21,8 +21,6 @@ from iec_api.models.meter_reading import MeterReadings from iec_api.models.remote_reading import ReadingResolution, RemoteReadingResponse -logger = getLogger(__name__) - class IecClient: """IEC API Client.""" @@ -382,7 +380,7 @@ async def override_id_token(self, id_token): :param id_token: The new token to be set. :return: None """ - logger.debug("Overriding jwt.py token: %s", id_token) + logger.debug(f"Overriding jwt.py token: {id_token}") self._token = JWT(access_token="", refresh_token="", token_type="", expires_in=0, scope="", id_token=id_token) self._token.id_token = id_token self.logged_in = True diff --git a/iec_api/login.py b/iec_api/login.py index 74cb445..ab031da 100644 --- a/iec_api/login.py +++ b/iec_api/login.py @@ -4,13 +4,13 @@ import re import string import time -from logging import getLogger from typing import Optional, Tuple import aiofiles import jwt import pkce from aiohttp import ClientSession +from loguru import logger from iec_api import commons from iec_api.models.exceptions import IECLoginError @@ -30,8 +30,6 @@ "&sessionToken={sessionToken}&code_challenge={challenge}" ) -logger = getLogger(__name__) - async def authorize_session(session: ClientSession, session_token) -> str: """ @@ -145,8 +143,8 @@ async def first_login(session: ClientSession, id_number: str) -> Tuple[str, str, return state_token, factor_id, session_token except Exception as error: - logger.warning("Failed at first login: %s", error) - raise IECLoginError(-1, "Failed at first login") + logger.warning(f"Failed at first login: {error}") + raise IECLoginError(-1, "Failed at first login") from error async def verify_otp_code(session: ClientSession, factor_id: str, state_token: str, otp_code: str) -> JWT: @@ -168,8 +166,8 @@ async def verify_otp_code(session: ClientSession, factor_id: str, state_token: s jwt_token = await get_access_token(session, code) return jwt_token except Exception as error: - logger.warning("Failed at OTP verification: %s", error) - raise IECLoginError(-1, "Failed at OTP verification") + logger.warning(f"Failed at OTP verification: {error}") + raise IECLoginError(-1, "Failed at OTP verification") from error async def manual_authorization(session: ClientSession, id_number) -> Optional[JWT]: # pragma: no cover diff --git a/pyproject.toml b/pyproject.toml index b6978c2..a6e32eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ requests = "^2.31.0" pkce = "^1.0.3" aiohttp = "^3.9.1" aiofiles = "^23.2.1" +loguru = "^0.7.2" [tool.poetry.dev-dependencies] pytest = "8.0.2"