From d9e3af91a3462a548e42e03a594e248e51f429f2 Mon Sep 17 00:00:00 2001 From: Rostyslav Bohomaz Date: Mon, 13 Nov 2023 18:36:38 +0200 Subject: [PATCH] WIP --- .gitignore | 3 +- liqpy/{api.py => api/__init__.py} | 87 ++--------------- liqpy/api/decoder.py | 41 ++++++++ liqpy/api/encoder.py | 76 +++++++++++++++ liqpy/{ => api}/exceptions.py | 4 +- liqpy/{ => api}/preprocess.py | 8 +- liqpy/{ => api}/validation.py | 50 +++------- liqpy/client.py | 44 +++++---- liqpy/data.py | 150 ------------------------------ liqpy/dev/__init__.py | 0 liqpy/{ => dev}/server.py | 4 +- liqpy/{ => dev}/testing.py | 0 liqpy/models/__init__.py | 0 liqpy/models/callback.py | 0 liqpy/models/common.py | 0 liqpy/models/request.py | 43 +++++++++ liqpy/util/__init__.py | 0 liqpy/{ => util}/convert.py | 62 +++++++++--- readme.ipynb | 13 ++- tests/test_json_encoder.py | 16 ++-- 20 files changed, 283 insertions(+), 318 deletions(-) rename liqpy/{api.py => api/__init__.py} (73%) create mode 100644 liqpy/api/decoder.py create mode 100644 liqpy/api/encoder.py rename liqpy/{ => api}/exceptions.py (98%) rename liqpy/{ => api}/preprocess.py (92%) rename liqpy/{ => api}/validation.py (90%) delete mode 100644 liqpy/data.py create mode 100644 liqpy/dev/__init__.py rename liqpy/{ => dev}/server.py (97%) rename liqpy/{ => dev}/testing.py (100%) create mode 100644 liqpy/models/__init__.py create mode 100644 liqpy/models/callback.py create mode 100644 liqpy/models/common.py create mode 100644 liqpy/models/request.py create mode 100644 liqpy/util/__init__.py rename liqpy/{ => util}/convert.py (60%) diff --git a/.gitignore b/.gitignore index 2754b76..ca9f8a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ __pycache__/ /venv/ -.env \ No newline at end of file +.env +.env.* diff --git a/liqpy/api.py b/liqpy/api/__init__.py similarity index 73% rename from liqpy/api.py rename to liqpy/api/__init__.py index c2cac80..9ac626b 100644 --- a/liqpy/api.py +++ b/liqpy/api/__init__.py @@ -1,28 +1,25 @@ from typing import TYPE_CHECKING, Any, AnyStr, Optional, Unpack -from functools import singledispatchmethod from enum import Enum -from dataclasses import asdict from urllib.parse import urljoin from base64 import b64encode, b64decode from hashlib import sha1 from json import loads, JSONEncoder -from uuid import UUID -from decimal import Decimal -from datetime import date, datetime, UTC +from datetime import datetime, UTC -from .data import FiscalItem, DetailAddenda, SplitRule +from .encoder import Encoder, JSONEncoder from .preprocess import Preprocessor, BasePreprocessor from .validation import Validator, BaseValidator +from .exceptions import exception if TYPE_CHECKING: from requests import Session, Response - from .types import LiqpayRequestDict - from .types.action import Action - from .types.post import Hooks, Proxies, Timeout, Verify, Cert + from liqpy.types import LiqpayRequestDict + from liqpy.types.action import Action + from liqpy.types.post import Hooks, Proxies, Timeout, Verify, Cert __all__ = ("Endpoint", "post", "sign", "encode", "decode", "request") @@ -30,24 +27,6 @@ URL = "https://www.liqpay.ua" VERSION = 3 -SENDER_KEYS = { - "sender_first_name", - "sender_last_name", - "sender_email", - "sender_address", - "sender_city", - "sender_country_code", - "sender_postal_code", - "sender_shipping_state", -} - -PRODUCT_KEYS = { - "product_category", - "product_description", - "product_name", - "product_url", -} - class Endpoint(Enum): REQUEST: str = "/api/request" @@ -57,58 +36,6 @@ def url(self) -> str: return urljoin(URL, self.value) -class LiqPayJSONEncoder(JSONEncoder): - date_fmt = r"%Y-%m-%d %H:%M:%S" - - def __init__(self) -> None: - super().__init__( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=False, - sort_keys=False, - indent=None, - separators=None, - default=None, - ) - - @singledispatchmethod - def default(self, o): - return super().default(o) - - @default.register - def _(self, o: Decimal) -> float: - return round(float(o), 4) - - @default.register - def _(self, o: datetime) -> str: - return o.astimezone(UTC).strftime(self.date_fmt) - - @default.register - def _(self, o: date) -> str: - return o.strftime(self.date_fmt) - - @default.register - def _(self, o: bytes) -> str: - return o.decode("utf-8") - - @default.register - def _(self, o: UUID) -> str: - return str(o) - - @default.register - def _(self, o: DetailAddenda) -> str: - return b64encode(self.encode(o.to_dict()).encode()).decode() - - @default.register - def _(self, o: SplitRule) -> dict: - return asdict(o) - - @default.register - def _(self, o: FiscalItem) -> dict: - return asdict(o) - - def is_sandbox(key: str, /) -> bool: return key.startswith("sandbox_") @@ -215,7 +142,7 @@ def encode( params = {key: value for key, value in params.items() if value is not None} if encoder is None: - encoder = LiqPayJSONEncoder() + encoder = Encoder() if preprocessor is None: preprocessor = Preprocessor() diff --git a/liqpy/api/decoder.py b/liqpy/api/decoder.py new file mode 100644 index 0000000..2e078e1 --- /dev/null +++ b/liqpy/api/decoder.py @@ -0,0 +1,41 @@ +from json import JSONDecoder +from ipaddress import IPv4Address + +from liqpy.util.convert import to_datetime + + +class Decoder(JSONDecoder): + def __init__(self): + super().__init__( + object_hook=self._object_hook, + parse_float=float, + parse_int=int, + parse_constant=None, + strict=True, + object_pairs_hook=None, + ) + self.create_date = to_datetime + self.end_date = to_datetime + self.completion_date = to_datetime + self.mpi_eci = int + self.ip = IPv4Address + self.refund_date_last = to_datetime + + def _object_hook(self, o: dict, /) -> dict: + for key, value in o.items(): + try: + fn = getattr(self, key, None) + + if not callable(fn): + continue + + processed = fn(value) + + if processed is not None: + o[key] = processed + + except Exception as e: + raise Exception(f"Failed to post convert {key} parameter.") from e + + return o + \ No newline at end of file diff --git a/liqpy/api/encoder.py b/liqpy/api/encoder.py new file mode 100644 index 0000000..54844cd --- /dev/null +++ b/liqpy/api/encoder.py @@ -0,0 +1,76 @@ +from functools import singledispatchmethod +from dataclasses import asdict + +from base64 import b64encode +from json import JSONEncoder + +from uuid import UUID +from decimal import Decimal +from datetime import date, datetime, UTC + +from liqpy.models.request import FiscalItem, DetailAddenda, SplitRule + + +__all__ = ("Encoder", "JSONEncoder") + + +class Encoder(JSONEncoder): + date_fmt = r"%Y-%m-%d %H:%M:%S" + + def __init__(self) -> None: + super().__init__( + skipkeys=False, + ensure_ascii=True, + check_circular=True, + allow_nan=False, + sort_keys=False, + indent=None, + separators=None, + default=None, + ) + + @singledispatchmethod + def default(self, o): + return super().default(o) + + @default.register + def _(self, o: Decimal) -> float: + return round(float(o), 4) + + @default.register + def _(self, o: datetime) -> str: + return o.astimezone(UTC).strftime(self.date_fmt) + + @default.register + def _(self, o: date) -> str: + return o.strftime(self.date_fmt) + + @default.register + def _(self, o: bytes) -> str: + return o.decode("utf-8") + + @default.register + def _(self, o: UUID) -> str: + return str(o) + + @default.register + def _(self, o: DetailAddenda) -> str: + data = { + "airLine": o.air_line, + "ticketNumber": o.ticket_number, + "passengerName": o.passenger_name, + "flightNumber": o.flight_number, + "originCity": o.origin_city, + "destinationCity": o.destination_city, + "departureDate": o.departure_date.strftime(r"%d%m%y"), + } + + return b64encode(self.encode(data).encode()).decode() + + @default.register + def _(self, o: SplitRule) -> dict: + return asdict(o) + + @default.register + def _(self, o: FiscalItem) -> dict: + return asdict(o) diff --git a/liqpy/exceptions.py b/liqpy/api/exceptions.py similarity index 98% rename from liqpy/exceptions.py rename to liqpy/api/exceptions.py index fb19a4e..063698d 100644 --- a/liqpy/exceptions.py +++ b/liqpy/api/exceptions.py @@ -3,7 +3,7 @@ if TYPE_CHECKING: from requests import Response - from .types.error import ( + from liqpy.types.error import ( LiqPayErrcode, LiqpayAntiFraudErrcode, LiqpayFinancialErrcode, @@ -97,7 +97,7 @@ def get_exception_cls(code: str | None = None) -> type[LiqPayException]: return LiqPayException -def exception_factory( +def exception( code: str | None = None, description: str | None = None, *, diff --git a/liqpy/preprocess.py b/liqpy/api/preprocess.py similarity index 92% rename from liqpy/preprocess.py rename to liqpy/api/preprocess.py index 3f12fcc..42fe5c8 100644 --- a/liqpy/preprocess.py +++ b/liqpy/api/preprocess.py @@ -1,12 +1,12 @@ from typing import TYPE_CHECKING, Optional -from datetime import timedelta -from .convert import to_datetime, to_milliseconds -from .data import DetailAddenda +from liqpy.models.request import DetailAddenda +from liqpy.util.convert import to_datetime, to_milliseconds if TYPE_CHECKING: from json import JSONEncoder - from .types.request import LiqpayRequestDict + + from liqpy.types.request import LiqpayRequestDict class BasePreprocessor: diff --git a/liqpy/validation.py b/liqpy/api/validation.py similarity index 90% rename from liqpy/validation.py rename to liqpy/api/validation.py index 593d329..39affde 100644 --- a/liqpy/validation.py +++ b/liqpy/api/validation.py @@ -1,15 +1,14 @@ from typing import TYPE_CHECKING -from functools import cache from datetime import datetime -from re import compile +from re import fullmatch from numbers import Number from uuid import UUID from urllib.parse import urlparse -from .data import DetailAddenda, SplitRule, FiscalItem, FiscalInfo +from liqpy.models.request import DetailAddenda, SplitRule, FiscalItem, FiscalInfo if TYPE_CHECKING: - from .types.request import ( + from liqpy.types.request import ( DetailAddendaDict, SplitRuleDict, FiscalItemDict, @@ -18,31 +17,6 @@ ) -@cache -def phone_pattern(): - return compile(r"\+?380\d{9}") - - -@cache -def card_cvv_pattern(): - return compile(r"\d{3}") - - -@cache -def card_number_pattern(): - return compile(r"\d{16}") - - -@cache -def card_exp_year_pattern(): - return compile(r"(\d{2})?\d{2}") - - -@cache -def card_exp_month_pattern(): - return compile(r"(0[1-9])|(1[0-2])") - - def noop(value, /, **kwargs): pass @@ -63,7 +37,7 @@ def string(value, /, *, max_len: int | None = None): def url(value, /, *, max_len: int | None = None): - string(value, max_len=max_len) + string(value, max_len=max_len) result = urlparse(value or "") assert result.scheme in ( "http", @@ -141,8 +115,8 @@ def resp_format(self, value, /, **kwargs): ), "format must be json, csv or xml" def phone(self, value, /, **kwargs): - assert phone_pattern().fullmatch( - value + assert fullmatch( + r"\+?380\d{9}", value ), "phone must be in format +380XXXXXXXXX or 380XXXXXXXXX" def sender_phone(self, value, /, **kwargs): @@ -155,19 +129,19 @@ def language(self, value, /, **kwargs): assert value in ("uk", "en"), "language must be uk or en" def card_number(self, value, /, **kwargs): - assert card_number_pattern().fullmatch(value), f"card must be 16 digits long" + assert fullmatch(r"\d{16}", value), f"card must be 16 digits long" def card_cvv(self, value, /, **kwargs): - assert card_cvv_pattern().fullmatch(value), f"cvv must be 3 digits long" + assert fullmatch(r"\d{3}", value), f"cvv must be 3 digits long" def card_exp_year(self, value, /, **kwargs): - assert card_exp_year_pattern().fullmatch( - value + assert fullmatch( + r"(\d{2})?\d{2}", value ), f"exp_year must be 2 or 4 digits long" def card_exp_month(self, value, /, **kwargs): - assert card_exp_month_pattern().fullmatch( - value + assert fullmatch( + r"(0[1-9])|(1[0-2])", value ), f"exp_month must be 2 digits long and between 01 and 12" def subscribe(self, value, /, **kwargs): diff --git a/liqpy/client.py b/liqpy/client.py index dbed7e6..cc893f7 100644 --- a/liqpy/client.py +++ b/liqpy/client.py @@ -11,16 +11,22 @@ from liqpy import __version__ -from .api import post, Endpoint, sign, request, encode, decode, VERSION, is_sandbox -from .exceptions import exception_factory -from .data import LiqpayCallback +from .api import ( + VERSION, + Endpoint, + post, + sign, + request, + encode, + decode, + is_sandbox, + exception, + BasePreprocessor, + BaseValidator, + JSONEncoder, +) if TYPE_CHECKING: - from json import JSONEncoder - - from .preprocess import BasePreprocessor - from .validation import BaseValidator - from .types.common import Language, Currency, SubscribePeriodicity, PayOption from .types.request import Format, Language, LiqpayRequestDict from .types.callback import LiqpayCallbackDict @@ -29,7 +35,7 @@ __all__ = ["Client"] -logger = getLogger(__name__) +logger = getLogger(__package__) CHECKOUT_ACTIONS = ( @@ -214,19 +220,22 @@ def request(self, action: str, **kwargs: "LiqpayRequestDict") -> dict: ) if not response.headers.get("Content-Type", "").startswith("application/json"): - raise exception_factory(response=response) + raise exception(response=response) data: dict = response.json() result: Optional[Literal["ok", "error"]] = data.pop("result", None) status = data.get("status") - err_code = data.pop("err_code", data.pop("code", None)) + err_code = data.pop("err_code", None) or data.pop("code", None) - if result == "ok" or (action in ("status", "data") and err_code is None): + if result == "ok": + return data + + if action in ("status", "data") and data.get("payment_id") is not None: return data if status in ("error", "failure") or result == "error": - raise exception_factory( + raise exception( code=err_code, description=data.pop("err_description", None), response=response, @@ -307,7 +316,7 @@ def checkout( if response.headers.get("Content-Type", "").startswith("application/json"): result = response.json() - raise exception_factory( + raise exception( code=result.pop("err_code", None), description=result.pop("err_description", None), response=response, @@ -367,7 +376,7 @@ def reports( if error is None: return output else: - raise exception_factory( + raise exception( code=error.pop("err_code"), description=error.pop("err_description"), response=response, @@ -479,7 +488,4 @@ def callback(self, /, data: AnyStr, signature: AnyStr, *, verify: bool = True): if version != VERSION: logger.warning("Callback version mismatch: %s != %s", version, VERSION) - try: - return LiqpayCallback(**result) - finally: - logger.warning("Failed to parse callback data.", extra=result) + return result diff --git a/liqpy/data.py b/liqpy/data.py deleted file mode 100644 index 184304c..0000000 --- a/liqpy/data.py +++ /dev/null @@ -1,150 +0,0 @@ -from typing import Literal, TYPE_CHECKING, Optional -from dataclasses import dataclass, asdict -from datetime import datetime -from numbers import Number -from ipaddress import ip_address, IPv4Address - -from .convert import to_datetime - -if TYPE_CHECKING: - from .types.common import Currency, Language, PayType - from .types.callback import ThreeDS, CallbackAction - from .types.error import LiqPayErrcode - from .types import status - - -def from_milliseconds(value: int) -> datetime: - return datetime.fromtimestamp(value / 1000) - - -@dataclass(kw_only=True) -class DetailAddenda: - air_line: str - ticket_number: str - passenger_name: str - flight_number: str - origin_city: str - destination_city: str - departure_date: datetime - - def __post_init__(self): - if not isinstance(self.departure_date, datetime): - self.departure_date = to_datetime(self.departure_date) - - def to_dict(self): - return { - "airLine": self.air_line, - "ticketNumber": self.ticket_number, - "passengerName": self.passenger_name, - "flightNumber": self.flight_number, - "originCity": self.origin_city, - "destinationCity": self.destination_city, - "departureDate": self.departure_date.strftime(r"%d%m%y"), - } - - -@dataclass(kw_only=True) -class SplitRule: - public_key: str - amount: Number - commission_payer: Literal["sender", "receiver"] - server_url: str - - -@dataclass(kw_only=True) -class FiscalItem: - id: int - amount: Number - cost: Number - price: Number - - -@dataclass(kw_only=True) -class FiscalInfo: - items: list[FiscalItem] - delivery_emails: list[str] - - -@dataclass(init=False) -class LiqpayCallback: - acq_id: int - action: "CallbackAction" - agent_commission: Number - amount: Number - amount_bonus: Number - amount_credit: Number - amount_debit: Number - authcode_credit: str | None = None - authcode_debit: str | None = None - card_token: str | None = None - commission_credit: Number - commission_debit: Number - completion_date: datetime | None = None - create_date: datetime - currency: "Currency" - currency_credit: "Currency" - currency_debit: "Currency" - customer: str | None = None - description: str - end_date: datetime - err_code: Optional["LiqPayErrcode"] = None - err_description: str | None = None - info: str | None = None - ip: IPv4Address | None = None - is_3ds: bool - language: "Language" - liqpay_order_id: str - mpi_eci: "ThreeDS" - order_id: str - payment_id: int - paytype: "PayType" - public_key: str - receiver_commission: Number - redirect_to: str | None = None - refund_date_last: datetime | None = None - rrn_credit: str | None = None - rrn_debit: str | None = None - sender_bonus: Number - sender_card_bank: str - sender_card_country: int - sender_card_mask2: str - sender_card_type: str - sender_commission: Number - sender_first_name: str | None = None - sender_last_name: str | None = None - sender_phone: str | None = None - status: "status.CallbackStatus" - transaction_id: str | None = None - token: str | None = None - type: str - version: Literal[3] - err_erc: Optional["LiqPayErrcode"] = None - product_category: str | None = None - product_description: str | None = None - product_name: str | None = None - product_url: str | None = None - refund_amount: Number | None = None - verifycode: str | None = None - - code: str | None = None - - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - - self.__post_init__() - - def __post_init__(self): - self.create_date = from_milliseconds(self.create_date) - self.end_date = from_milliseconds(self.end_date) - - if self.completion_date is not None: - self.completion_date = from_milliseconds(self.completion_date) - - if self.refund_date_last is not None: - self.refund_date_last = from_milliseconds(self.refund_date_last) - - if self.ip is not None: - self.ip = ip_address(self.ip) - - self.mpi_eci = int(self.mpi_eci) diff --git a/liqpy/dev/__init__.py b/liqpy/dev/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/liqpy/server.py b/liqpy/dev/server.py similarity index 97% rename from liqpy/server.py rename to liqpy/dev/server.py index 75e9f32..8cd0c15 100644 --- a/liqpy/server.py +++ b/liqpy/dev/server.py @@ -3,10 +3,10 @@ from http.server import HTTPServer, BaseHTTPRequestHandler from urllib.parse import parse_qs -from .client import Client +from liqpy.client import Client if TYPE_CHECKING: - from .types import LiqpayCallbackDict + from liqpy.types import LiqpayCallbackDict class LiqpayHandler(BaseHTTPRequestHandler): diff --git a/liqpy/testing.py b/liqpy/dev/testing.py similarity index 100% rename from liqpy/testing.py rename to liqpy/dev/testing.py diff --git a/liqpy/models/__init__.py b/liqpy/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/liqpy/models/callback.py b/liqpy/models/callback.py new file mode 100644 index 0000000..e69de29 diff --git a/liqpy/models/common.py b/liqpy/models/common.py new file mode 100644 index 0000000..e69de29 diff --git a/liqpy/models/request.py b/liqpy/models/request.py new file mode 100644 index 0000000..cec5e84 --- /dev/null +++ b/liqpy/models/request.py @@ -0,0 +1,43 @@ +from typing import Literal +from dataclasses import dataclass +from datetime import date +from numbers import Number + +from liqpy.util.convert import to_date + + +@dataclass(kw_only=True) +class DetailAddenda: + air_line: str + ticket_number: str + passenger_name: str + flight_number: str + origin_city: str + destination_city: str + departure_date: date + + def __post_init__(self): + self.departure_date = to_date(self.departure_date) + + +@dataclass(kw_only=True) +class SplitRule: + public_key: str + amount: Number + commission_payer: Literal["sender", "receiver"] + server_url: str + + +@dataclass(kw_only=True) +class FiscalItem: + id: int + amount: Number + cost: Number + price: Number + + +@dataclass(kw_only=True) +class FiscalInfo: + items: list[FiscalItem] + delivery_emails: list[str] + diff --git a/liqpy/util/__init__.py b/liqpy/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/liqpy/convert.py b/liqpy/util/convert.py similarity index 60% rename from liqpy/convert.py rename to liqpy/util/convert.py index 7f28a9b..b75055f 100644 --- a/liqpy/convert.py +++ b/liqpy/util/convert.py @@ -1,13 +1,41 @@ from typing import overload, TYPE_CHECKING -from functools import singledispatch, cache +from functools import singledispatch from numbers import Number -from datetime import datetime, UTC, timedelta -from re import compile +from datetime import datetime, UTC, timedelta, date -@cache -def date_pattern(flags: int = 0): - return compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}", flags=flags) +def from_milliseconds(value: int) -> datetime: + return datetime.fromtimestamp(value / 1000) + + +@singledispatch +def to_date(value, **kwargs) -> date: + raise NotImplementedError(f"Unsupported type: {type(value)}") + + +@to_date.register +def _(value: datetime, **kwargs): + return value.date() + + +@to_date.register +def _(value: date, **kwargs): + return value + + +@to_date.register +def _(value: str, **kwargs): + return date.fromisoformat(value) + + +@to_date.register +def _(value: timedelta, **kwargs): + return date.today() + value + + +@to_date.register +def _(value: Number, **kwargs): + return to_date(date.fromtimestamp(float(value))) @singledispatch @@ -22,10 +50,7 @@ def _(value: datetime, **kwargs): @to_datetime.register def _(value: str, **kwargs): - if date_pattern().fullmatch(value): - return datetime.strptime(value, r"%Y-%m-%d %H:%M:%S") - else: - return datetime.fromisoformat(value) + return datetime.fromisoformat(value) @to_datetime.register @@ -64,9 +89,24 @@ def _(value: timedelta, **kwargs): if TYPE_CHECKING: + @overload + def to_date(value: Number, **kwargs) -> date: + ... + + @overload + def to_date(value: date, **kwargs) -> date: + ... + + @overload + def to_date(value: str, **kwargs) -> date: + ... + + @overload + def to_date(value: timedelta, **kwargs) -> date: + ... @overload - def to_datetime(value: Number, **kwargs) -> datetime: + def to_date(value: Number, **kwargs) -> date: ... @overload diff --git a/readme.ipynb b/readme.ipynb index 648ec92..bfee2ff 100644 --- a/readme.ipynb +++ b/readme.ipynb @@ -54,7 +54,7 @@ "from pprint import pprint\n", "from datetime import date, datetime, timedelta, UTC\n", "\n", - "from liqpy.testing import TestCard, gen_card_cvv, gen_card_expire" + "from liqpy.dev.testing import TestCard, gen_card_cvv, gen_card_expire" ] }, { @@ -168,7 +168,7 @@ "metadata": {}, "outputs": [], "source": [ - "from liqpy.exceptions import LiqPayException\n", + "from liqpy.api.exceptions import LiqPayException\n", "\n", "try:\n", " card_exp_month, card_exp_year = gen_card_expire(valid=True)\n", @@ -354,8 +354,15 @@ "metadata": {}, "outputs": [], "source": [ - "client.unsubscribe(order_id=order_id)" + "client.unsubscribe(order_id)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/tests/test_json_encoder.py b/tests/test_json_encoder.py index 972c5b7..cc21f8d 100644 --- a/tests/test_json_encoder.py +++ b/tests/test_json_encoder.py @@ -4,25 +4,25 @@ from pytest import fixture -from liqpy.api import LiqPayJSONEncoder, encode +from liqpy.api import Encoder, encode from liqpy.util import DetailAddenda @fixture def encoder(): - return LiqPayJSONEncoder() + return Encoder() -def test_encode_bytes(encoder: LiqPayJSONEncoder): +def test_encode_bytes(encoder: Encoder): assert encoder.encode(b"") == '""' assert encoder.encode(b"test") == '"test"' -def test_encode_date(encoder: LiqPayJSONEncoder): +def test_encode_date(encoder: Encoder): assert encoder.encode(date(2021, 1, 2)) == '"2021-01-02 00:00:00"' -def test_encode_datetime(encoder: LiqPayJSONEncoder): +def test_encode_datetime(encoder: Encoder): assert ( encoder.encode(datetime(2021, 1, 2, 3, 4, 5, tzinfo=UTC)) == '"2021-01-02 03:04:05"' @@ -41,19 +41,19 @@ def test_encode_datetime(encoder: LiqPayJSONEncoder): ) -def test_encode_uuid(encoder: LiqPayJSONEncoder): +def test_encode_uuid(encoder: Encoder): value = "123e4567-e89b-12d3-a456-426614174000" assert encoder.encode(UUID(value)) == f'"{value}"' -def test_encode_decimal(encoder: LiqPayJSONEncoder): +def test_encode_decimal(encoder: Encoder): assert encoder.encode(Decimal(1)) == "1.0" assert encoder.encode(Decimal("1.0")) == "1.0" assert encoder.encode(Decimal(1.0)) == "1.0" assert encoder.encode(Decimal("0.0001")) == "0.0001" -def test_encode_dae(encoder: LiqPayJSONEncoder): +def test_encode_dae(encoder: Encoder): dae = DetailAddenda( air_line="Avia", ticket_number="ACSFD12354SA",