From 94cdc4b47fa1942a379c016a8a71430ba50dcb34 Mon Sep 17 00:00:00 2001 From: Trevor Visser Date: Sun, 19 May 2024 17:37:59 +0200 Subject: [PATCH 1/3] test: fixed exchange money test --- README.md | 4 +- .../foreign_exchange/post/exchange_money.py | 10 +- pyrevolut/client/__init__.py | 1 + pyrevolut/client/base.py | 12 +- pyrevolut/exceptions/__init__.py | 1 + .../exceptions/internal_revolut_error.py | 8 + tests/test_foreign_exchange.py | 220 +++++++++--------- tests/test_transfers.py | 100 +++++++- 8 files changed, 240 insertions(+), 116 deletions(-) create mode 100644 pyrevolut/exceptions/internal_revolut_error.py diff --git a/README.md b/README.md index af144ce..209605f 100644 --- a/README.md +++ b/README.md @@ -117,9 +117,9 @@ The SDK currently supports the following APIs: - [x] Create a counterparty (Personal) - [x] Create a counterparty (Business) - [x] Validate an account name (CoP) -- [ ] Foreign exchange +- [x] Foreign exchange - [x] Get an exchange rate - - [ ] Exchange money + - [x] Exchange money - [ ] Payment drafts - [x] Retrieve all payments drafts - [ ] Create a payment draft diff --git a/pyrevolut/api/foreign_exchange/post/exchange_money.py b/pyrevolut/api/foreign_exchange/post/exchange_money.py index 7bff0d8..cfb71af 100644 --- a/pyrevolut/api/foreign_exchange/post/exchange_money.py +++ b/pyrevolut/api/foreign_exchange/post/exchange_money.py @@ -1,6 +1,6 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal +# from decimal import Decimal from pydantic import BaseModel, Field, model_validator, ConfigDict from pydantic_extra_types.currency_code import Currency @@ -46,8 +46,10 @@ class ModelFrom(BaseModel): Currency, Field(description="The currency to sell in ISO 4217 format."), ] + # Originally Decimal | None but Revolut API fails when Decimal -> str is used + # So, we use float | None instead amount: Annotated[ - Decimal | None, + float | None, Field( description="The amount of currency. Specify ONLY if you want to sell currency." ), @@ -66,8 +68,10 @@ class ModelTo(BaseModel): Currency, Field(description="The currency to buy in ISO 4217 format."), ] + # Originally Decimal | None but Revolut API fails when Decimal -> str is used + # So, we use float | None instead amount: Annotated[ - Decimal | None, + float | None, Field( description="The amount of currency. Specify ONLY if you want to buy currency." ), diff --git a/pyrevolut/client/__init__.py b/pyrevolut/client/__init__.py index 4988a62..29c2dac 100644 --- a/pyrevolut/client/__init__.py +++ b/pyrevolut/client/__init__.py @@ -1,5 +1,6 @@ """This module contains the client implementation for the Revolut API.""" # flake8: noqa: F401 +from .base import ModelError from .synchronous import Client from .asynchronous import AsyncClient diff --git a/pyrevolut/client/base.py b/pyrevolut/client/base.py index 96b9568..274704f 100644 --- a/pyrevolut/client/base.py +++ b/pyrevolut/client/base.py @@ -15,7 +15,11 @@ save_creds, load_creds, ) -from pyrevolut.exceptions import PyRevolutAPIException, BadRequestException +from pyrevolut.exceptions import ( + PyRevolutAPIException, + BadRequestException, + InternalRevolutError, +) BM = TypeVar("BM", bound=Type[BaseModel]) @@ -25,7 +29,7 @@ class ModelError(BaseModel): """Model for the error response""" - code: Annotated[str, Field(description="The error code")] + code: Annotated[int, Field(description="The error code")] message: Annotated[str, Field(description="The error message")] @@ -160,6 +164,8 @@ def process_response( if error_response == "raise": if response.status_code == 400: raise BadRequestException(response.text) + elif response.status_code // 100 == 5: + raise InternalRevolutError(response.text) raise PyRevolutAPIException(response.text) elif error_response == "raw": return response.json() @@ -205,7 +211,7 @@ def log_request(self, request: Request): None """ logging.info( - f"Request: {request.method} {request.url} - {request.headers} - {request.content.decode() if request.content else None}" + f"Request: {request.method} {request.url} - {request.headers} - {request.read().decode()}" ) def log_response(self, response: Response): diff --git a/pyrevolut/exceptions/__init__.py b/pyrevolut/exceptions/__init__.py index 7fb5bce..18d1552 100644 --- a/pyrevolut/exceptions/__init__.py +++ b/pyrevolut/exceptions/__init__.py @@ -4,4 +4,5 @@ from .common import PyRevolutAPIException from .bad_request import BadRequestException +from .internal_revolut_error import InternalRevolutError from .invalid_environment import InvalidEnvironmentException diff --git a/pyrevolut/exceptions/internal_revolut_error.py b/pyrevolut/exceptions/internal_revolut_error.py new file mode 100644 index 0000000..4e4d4bd --- /dev/null +++ b/pyrevolut/exceptions/internal_revolut_error.py @@ -0,0 +1,8 @@ +from .common import PyRevolutAPIException + + +class InternalRevolutError(PyRevolutAPIException): + """An internal error in the Revolut API. This is a bug in the Revolut API. + Please report this issue to the Revolut API team.""" + + pass diff --git a/tests/test_foreign_exchange.py b/tests/test_foreign_exchange.py index a9cbb71..25d5b2c 100644 --- a/tests/test_foreign_exchange.py +++ b/tests/test_foreign_exchange.py @@ -7,7 +7,7 @@ from pyrevolut.client import Client, AsyncClient from pyrevolut.api import EnumAccountState, EnumTransactionState -from pyrevolut.exceptions import PyRevolutAPIException +from pyrevolut.exceptions import InternalRevolutError def test_sync_get_exchange_rate(sync_client: Client): @@ -37,63 +37,66 @@ def test_sync_get_exchange_rate(sync_client: Client): def test_sync_exchange_money(sync_client: Client): """Test the sync `exchange_money` foreign exchange method""" - with pytest.raises(PyRevolutAPIException, match="Something went wrong"): - # Get all accounts - accounts = sync_client.Accounts.get_all_accounts() - time.sleep(random.randint(1, 3)) + # Get all accounts + accounts = sync_client.Accounts.get_all_accounts() + time.sleep(random.randint(1, 3)) - # Get GBP and EUR accounts - gbp_account = next( - account - for account in accounts - if account["currency"] == "GBP" - and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") - ) - gbp_balance = gbp_account["balance"] - eur_account = next( - account - for account in accounts - if account["currency"] == "EUR" - and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") - ) - eur_balance = eur_account["balance"] + # Get GBP and EUR accounts + gbp_account = next( + account + for account in accounts + if account["currency"] == "GBP" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] > Decimal("0") + ) + gbp_balance = gbp_account["balance"] + eur_account = next( + account + for account in accounts + if account["currency"] == "EUR" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] > Decimal("0") + ) + eur_balance = eur_account["balance"] - # Exchange 1 EUR from EUR to GBP - response = sync_client.ForeignExchange.exchange_money( - request_id=str(uuid4()), - from_account_id=eur_account["id"], - from_currency="EUR", - to_account_id=gbp_account["id"], - to_currency="GBP", - from_amount=Decimal("1"), - to_amount=None, - reference="PyRevolut Test", - ) - time.sleep(random.randint(1, 3)) - assert response["state"] == EnumTransactionState.COMPLETED + # Exchange 1 EUR from EUR to GBP + response = sync_client.ForeignExchange.exchange_money( + request_id=str(uuid4()), + from_account_id=eur_account["id"], + from_currency="EUR", + to_account_id=gbp_account["id"], + to_currency="GBP", + from_amount=Decimal("1"), + to_amount=None, + reference="PyRevolut Test", + ) + time.sleep(random.randint(1, 3)) + assert response["state"] == EnumTransactionState.COMPLETED - # Check balances - accounts = sync_client.Accounts.get_all_accounts() - time.sleep(random.randint(1, 3)) - gbp_balance2 = next( - account["balance"] - for account in accounts - if account["currency"] == "GBP" - and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") - ) - eur_balance2 = next( - account["balance"] - for account in accounts - if account["currency"] == "EUR" - and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") - ) - assert gbp_balance2 > gbp_balance - assert eur_balance2 == eur_balance - Decimal("1") + # Check balances + accounts = sync_client.Accounts.get_all_accounts() + time.sleep(random.randint(1, 3)) + gbp_balance2 = next( + account["balance"] + for account in accounts + if account["currency"] == "GBP" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] > Decimal("0") + ) + eur_balance2 = next( + account["balance"] + for account in accounts + if account["currency"] == "EUR" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] > Decimal("0") + ) + assert gbp_balance2 > gbp_balance + assert eur_balance2 == eur_balance - Decimal("1") + with pytest.raises( + InternalRevolutError, + match="Oops! An error occurred while processing your request. It has been logged for further investigation.", + ): # Exchange 1 EUR from GBP to EUR response = sync_client.ForeignExchange.exchange_money( request_id=str(uuid4()), @@ -157,63 +160,66 @@ async def test_async_get_exchange_rate(async_client: AsyncClient): async def test_async_exchange_money(async_client: AsyncClient): """Test the async `exchange_money` foreign exchange method""" - with pytest.raises(PyRevolutAPIException, match="Something went wrong"): - # Get all accounts - accounts = await async_client.Accounts.get_all_accounts() - await asyncio.sleep(random.randint(1, 3)) + # Get all accounts + accounts = await async_client.Accounts.get_all_accounts() + await asyncio.sleep(random.randint(1, 3)) - # Get GBP and EUR accounts - gbp_account = next( - account - for account in accounts - if account["currency"] == "GBP" - and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") - ) - gbp_balance = gbp_account["balance"] - eur_account = next( - account - for account in accounts - if account["currency"] == "EUR" - and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") - ) - eur_balance = eur_account["balance"] + # Get GBP and EUR accounts + gbp_account = next( + account + for account in accounts + if account["currency"] == "GBP" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] > Decimal("0") + ) + gbp_balance = gbp_account["balance"] + eur_account = next( + account + for account in accounts + if account["currency"] == "EUR" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] > Decimal("0") + ) + eur_balance = eur_account["balance"] - # Exchange 1 EUR from EUR to GBP - response = await async_client.ForeignExchange.exchange_money( - request_id=str(uuid4()), - from_account_id=eur_account["id"], - from_currency="EUR", - to_account_id=gbp_account["id"], - to_currency="GBP", - from_amount=Decimal("1"), - to_amount=None, - reference="PyRevolut Test", - ) - await asyncio.sleep(random.randint(1, 3)) - assert response["state"] == EnumTransactionState.COMPLETED + # Exchange 1 EUR from EUR to GBP + response = await async_client.ForeignExchange.exchange_money( + request_id=str(uuid4()), + from_account_id=eur_account["id"], + from_currency="EUR", + to_account_id=gbp_account["id"], + to_currency="GBP", + from_amount=Decimal("1"), + to_amount=None, + reference="PyRevolut Test", + ) + await asyncio.sleep(random.randint(1, 3)) + assert response["state"] == EnumTransactionState.COMPLETED - # Check balances - accounts = await async_client.Accounts.get_all_accounts() - await asyncio.sleep(random.randint(1, 3)) - gbp_balance2 = next( - account["balance"] - for account in accounts - if account["currency"] == "GBP" - and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") - ) - eur_balance2 = next( - account["balance"] - for account in accounts - if account["currency"] == "EUR" - and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") - ) - assert gbp_balance2 > gbp_balance - assert eur_balance2 == eur_balance - Decimal("1") + # Check balances + accounts = await async_client.Accounts.get_all_accounts() + await asyncio.sleep(random.randint(1, 3)) + gbp_balance2 = next( + account["balance"] + for account in accounts + if account["currency"] == "GBP" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] > Decimal("0") + ) + eur_balance2 = next( + account["balance"] + for account in accounts + if account["currency"] == "EUR" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] > Decimal("0") + ) + assert gbp_balance2 > gbp_balance + assert eur_balance2 == eur_balance - Decimal("1") + with pytest.raises( + InternalRevolutError, + match="Oops! An error occurred while processing your request. It has been logged for further investigation.", + ): # Exchange 1 EUR from GBP to EUR response = await async_client.ForeignExchange.exchange_money( request_id=str(uuid4()), diff --git a/tests/test_transfers.py b/tests/test_transfers.py index 74af8c1..cedfb88 100644 --- a/tests/test_transfers.py +++ b/tests/test_transfers.py @@ -124,6 +124,16 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): ) eur_balance = eur_account["balance"] + # Get GBP account + gbp_account = next( + account + for account in accounts + if account["currency"] == "GBP" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] + ) + gbp_balance = gbp_account["balance"] + # If there is no EUR balance, simulate a top up if eur_balance < Decimal("1"): response = sync_client.Simulations.simulate_account_topup( @@ -136,6 +146,18 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): time.sleep(random.randint(1, 3)) assert response["state"] == EnumTransactionState.COMPLETED + # If there is no GBP balance, simulate a top up + if gbp_balance < Decimal("1"): + response = sync_client.Simulations.simulate_account_topup( + account_id=gbp_account["id"], + amount=Decimal("1"), + currency="GBP", + reference="PyRevolut Test", + state=EnumTransactionState.COMPLETED, + ) + time.sleep(random.randint(1, 3)) + assert response["state"] == EnumTransactionState.COMPLETED + # Get all counterparties counterparties = sync_client.Counterparties.get_all_counterparties() @@ -155,7 +177,7 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): if acc["currency"] == "EUR" and acc["iban"] is not None ][0] - # Create a transfer to the EUR counterparty + # Create a transfer from the EUR account to the EUR counterparty response = sync_client.Transfers.create_transfer_to_another_account( request_id=str(uuid4()), account_id=eur_account["id"], @@ -182,6 +204,33 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): time.sleep(random.randint(1, 3)) assert response["state"] == EnumTransactionState.COMPLETED + # Create a transfer from the GBP account to the EUR counterparty + response = sync_client.Transfers.create_transfer_to_another_account( + request_id=str(uuid4()), + account_id=gbp_account["id"], + counterparty_id=eur_counterparty["id"], + amount=Decimal("1"), + currency="EUR", + counterparty_account_id=eur_counterparty_account["id"], + reference="PyRevolut Test", + transfer_reason_code=EnumTransferReasonCode.FAMILY_SUPPORT, + ) + time.sleep(random.randint(1, 3)) + assert response["state"] == EnumTransactionState.PENDING + + # Check balance + account = sync_client.Accounts.get_account(account_id=gbp_account["id"]) + time.sleep(random.randint(1, 3)) + assert account["balance"] < gbp_balance # Not exact because of the exchange rate + + # Complete the transfer via simulation + response = sync_client.Simulations.simulate_transfer_state_update( + transfer_id=response["id"], + action=EnumSimulateTransferStateAction.COMPLETE, + ) + time.sleep(random.randint(1, 3)) + assert response["state"] == EnumTransactionState.COMPLETED + @pytest.mark.asyncio async def test_async_get_transfer_reasons(async_client: Client): @@ -295,6 +344,16 @@ async def test_async_create_transfer_to_another_account(async_client: Client): ) eur_balance = eur_account["balance"] + # Get GBP account + gbp_account = next( + account + for account in accounts + if account["currency"] == "GBP" + and account["state"] == EnumAccountState.ACTIVE + and account["balance"] + ) + gbp_balance = gbp_account["balance"] + # If there is no EUR balance, simulate a top up if eur_balance < Decimal("1"): response = await async_client.Simulations.simulate_account_topup( @@ -307,6 +366,18 @@ async def test_async_create_transfer_to_another_account(async_client: Client): await asyncio.sleep(random.randint(1, 3)) assert response["state"] == EnumTransactionState.COMPLETED + # If there is no GBP balance, simulate a top up + if gbp_balance < Decimal("1"): + response = await async_client.Simulations.simulate_account_topup( + account_id=gbp_account["id"], + amount=Decimal("1"), + currency="GBP", + reference="PyRevolut Test", + state=EnumTransactionState.COMPLETED, + ) + await asyncio.sleep(random.randint(1, 3)) + assert response["state"] == EnumTransactionState.COMPLETED + # Get all counterparties counterparties = await async_client.Counterparties.get_all_counterparties() @@ -352,3 +423,30 @@ async def test_async_create_transfer_to_another_account(async_client: Client): ) await asyncio.sleep(random.randint(1, 3)) assert response["state"] == EnumTransactionState.COMPLETED + + # Create a transfer from the GBP account to the EUR counterparty + response = await async_client.Transfers.create_transfer_to_another_account( + request_id=str(uuid4()), + account_id=gbp_account["id"], + counterparty_id=eur_counterparty["id"], + amount=Decimal("1"), + currency="EUR", + counterparty_account_id=eur_counterparty_account["id"], + reference="PyRevolut Test", + transfer_reason_code=EnumTransferReasonCode.FAMILY_SUPPORT, + ) + await asyncio.sleep(random.randint(1, 3)) + assert response["state"] == EnumTransactionState.PENDING + + # Check balance + account = await async_client.Accounts.get_account(account_id=gbp_account["id"]) + await asyncio.sleep(random.randint(1, 3)) + assert account["balance"] < gbp_balance # Not exact because of the exchange rate + + # Complete the transfer via simulation + response = await async_client.Simulations.simulate_transfer_state_update( + transfer_id=response["id"], + action=EnumSimulateTransferStateAction.COMPLETE, + ) + await asyncio.sleep(random.randint(1, 3)) + assert response["state"] == EnumTransactionState.COMPLETED From d8505a562c470d00004dcdc5925451283753f752 Mon Sep 17 00:00:00 2001 From: Trevor Visser Date: Sun, 19 May 2024 18:45:59 +0200 Subject: [PATCH 2/3] fix: replaced all decimals with floats --- pyproject.toml | 2 + pyrevolut/api/accounts/resources/account.py | 3 +- pyrevolut/api/cards/endpoint/asynchronous.py | 59 +++++++++---------- pyrevolut/api/cards/endpoint/synchronous.py | 59 +++++++++---------- pyrevolut/api/common/models/amount.py | 10 ++-- .../foreign_exchange/endpoint/asynchronous.py | 13 ++-- .../foreign_exchange/endpoint/synchronous.py | 13 ++-- .../foreign_exchange/get/get_exchange_rate.py | 3 +- .../foreign_exchange/post/exchange_money.py | 5 -- .../resources/foreign_exchange.py | 3 +- .../payment_drafts/endpoint/asynchronous.py | 5 +- .../payment_drafts/endpoint/synchronous.py | 5 +- .../get/retrieve_payment_draft.py | 3 +- .../post/create_payment_draft.py | 3 +- .../api/payout_links/endpoint/asynchronous.py | 5 +- .../api/payout_links/endpoint/synchronous.py | 5 +- .../payout_links/post/create_payout_link.py | 3 +- .../api/payout_links/resources/payout_link.py | 3 +- .../api/simulations/endpoint/asynchronous.py | 5 +- .../api/simulations/endpoint/synchronous.py | 5 +- .../post/simulate_account_topup.py | 3 +- .../api/transactions/resources/transaction.py | 9 ++- .../api/transfers/endpoint/asynchronous.py | 9 ++- .../api/transfers/endpoint/synchronous.py | 9 ++- .../create_transfer_to_another_account.py | 3 +- .../post/move_money_between_accounts.py | 3 +- .../webhooks/resources/transaction_created.py | 9 ++- pyrevolut/client/base.py | 4 +- tests/conftest.py | 9 ++- tests/test_foreign_exchange.py | 33 +++++------ tests/test_payment_drafts.py | 9 ++- tests/test_payout_links.py | 9 ++- tests/test_simulations.py | 33 +++++------ tests/test_transfers.py | 49 ++++++++------- 34 files changed, 186 insertions(+), 217 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 19ad2f2..f873b60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,8 @@ name = "pyrevolut" version = "0.6.0" description = "An unofficial Python API Wrapper for the Revolut Business API" authors = ["Trevor Visser "] +license = "MIT" +homepage = "https://github.com/Trevypants/pyrevolut" readme = "README.md" [tool.poetry.scripts] diff --git a/pyrevolut/api/accounts/resources/account.py b/pyrevolut/api/accounts/resources/account.py index af421f3..85bef32 100644 --- a/pyrevolut/api/accounts/resources/account.py +++ b/pyrevolut/api/accounts/resources/account.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency @@ -23,7 +22,7 @@ class ResourceAccount(BaseModel): Field(description="The account name."), ] = None balance: Annotated[ - Decimal, + float, Field(description="The current balance on the account."), ] currency: Annotated[ diff --git a/pyrevolut/api/cards/endpoint/asynchronous.py b/pyrevolut/api/cards/endpoint/asynchronous.py index 007f405..607062c 100644 --- a/pyrevolut/api/cards/endpoint/asynchronous.py +++ b/pyrevolut/api/cards/endpoint/asynchronous.py @@ -1,6 +1,5 @@ from typing import Literal, Type from uuid import UUID -from decimal import Decimal from datetime import datetime from pydantic import BaseModel @@ -139,19 +138,19 @@ async def create_card( label: str | None = None, accounts: list[UUID] | None = None, categories: list[EnumMerchantCategory] | None = None, - single_limit_amount: Decimal | None = None, + single_limit_amount: float | None = None, single_limit_currency: str | None = None, - day_limit_amount: Decimal | None = None, + day_limit_amount: float | None = None, day_limit_currency: str | None = None, - week_limit_amount: Decimal | None = None, + week_limit_amount: float | None = None, week_limit_currency: str | None = None, - month_limit_amount: Decimal | None = None, + month_limit_amount: float | None = None, month_limit_currency: str | None = None, - quarter_limit_amount: Decimal | None = None, + quarter_limit_amount: float | None = None, quarter_limit_currency: str | None = None, - year_limit_amount: Decimal | None = None, + year_limit_amount: float | None = None, year_limit_currency: str | None = None, - all_time_limit_amount: Decimal | None = None, + all_time_limit_amount: float | None = None, all_time_limit_currency: str | None = None, **kwargs, ) -> dict | CreateCard.Response: @@ -179,31 +178,31 @@ async def create_card( The list of accounts to link to the card. If not specified, all accounts will be linked. categories : list[EnumMerchantCategory] | None The list of merchant categories to link to the card. If not specified, all categories will be linked. - single_limit_amount : Decimal | None + single_limit_amount : float | None The maximum amount for a single transaction. single_limit_currency : str | None The currency of the single transaction limit. - day_limit_amount : Decimal | None + day_limit_amount : float | None The maximum amount for transactions in a day. day_limit_currency : str | None The currency of the day limit. - week_limit_amount : Decimal | None + week_limit_amount : float | None The maximum amount for transactions in a week. week_limit_currency : str | None The currency of the week limit. - month_limit_amount : Decimal | None + month_limit_amount : float | None The maximum amount for transactions in a month. month_limit_currency : str | None The currency of the month limit. - quarter_limit_amount : Decimal | None + quarter_limit_amount : float | None The maximum amount for transactions in a quarter. quarter_limit_currency : str | None The currency of the quarter limit. - year_limit_amount : Decimal | None + year_limit_amount : float | None The maximum amount for transactions in a year. year_limit_currency : str | None The currency of the year limit. - all_time_limit_amount : Decimal | None + all_time_limit_amount : float | None The maximum amount for transactions in the card's lifetime. all_time_limit_currency : str | None The currency of the all-time limit. @@ -381,19 +380,19 @@ async def update_card( card_id: UUID, label: str | None = None, categories: list[EnumMerchantCategory] | Literal["null"] | None = None, - single_limit_amount: Decimal | Literal["null"] | None = None, + single_limit_amount: float | Literal["null"] | None = None, single_limit_currency: str | Literal["null"] | None = None, - day_limit_amount: Decimal | Literal["null"] | None = None, + day_limit_amount: float | Literal["null"] | None = None, day_limit_currency: str | Literal["null"] | None = None, - week_limit_amount: Decimal | Literal["null"] | None = None, + week_limit_amount: float | Literal["null"] | None = None, week_limit_currency: str | Literal["null"] | None = None, - month_limit_amount: Decimal | Literal["null"] | None = None, + month_limit_amount: float | Literal["null"] | None = None, month_limit_currency: str | Literal["null"] | None = None, - quarter_limit_amount: Decimal | Literal["null"] | None = None, + quarter_limit_amount: float | Literal["null"] | None = None, quarter_limit_currency: str | Literal["null"] | None = None, - year_limit_amount: Decimal | Literal["null"] | None = None, + year_limit_amount: float | Literal["null"] | None = None, year_limit_currency: str | Literal["null"] | None = None, - all_time_limit_amount: Decimal | Literal["null"] | None = None, + all_time_limit_amount: float | Literal["null"] | None = None, all_time_limit_currency: str | Literal["null"] | None = None, **kwargs, ) -> dict | UpdateCardDetails.Response: @@ -410,43 +409,43 @@ async def update_card( categories : list[EnumMerchantCategory] | Literal["null"] | None The list of merchant categories to link to the card. If set to 'null', all categories will be linked. - single_limit_amount : Decimal | Literal["null"] | None + single_limit_amount : float | Literal["null"] | None The maximum amount for a single transaction. If set to 'null', the limit will be removed. single_limit_currency : str | Literal["null"] | None The currency of the single transaction limit. If set to 'null', the limit will be removed. - day_limit_amount : Decimal | Literal["null"] | None + day_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a day. If set to 'null', the limit will be removed. day_limit_currency : str | Literal["null"] | None The currency of the day limit. If set to 'null', the limit will be removed. - week_limit_amount : Decimal | Literal["null"] | None + week_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a week. If set to 'null', the limit will be removed. week_limit_currency : str | Literal["null"] | None The currency of the week limit. If set to 'null', the limit will be removed. - month_limit_amount : Decimal | Literal["null"] | None + month_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a month. If set to 'null', the limit will be removed. month_limit_currency : str | Literal["null"] | None The currency of the month limit. If set to 'null', the limit will be removed. - quarter_limit_amount : Decimal | Literal["null"] | None + quarter_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a quarter. If set to 'null', the limit will be removed. quarter_limit_currency : str | Literal["null"] | None The currency of the quarter limit. If set to 'null', the limit will be removed. - year_limit_amount : Decimal | Literal["null"] | None + year_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a year. If set to 'null', the limit will be removed. year_limit_currency : str | Literal["null"] | None The currency of the year limit. If set to 'null', the limit will be removed. - all_time_limit_amount : Decimal | Literal["null"] | None + all_time_limit_amount : float | Literal["null"] | None The maximum amount for transactions in the card's lifetime. If set to 'null', the limit will be removed. all_time_limit_currency : str | Literal["null"] | None @@ -575,7 +574,7 @@ async def delete_card( def __process_limit_model( self, model: Type[BaseModel], - amount: Decimal | None, + amount: float | None, currency: str | None, ): """ diff --git a/pyrevolut/api/cards/endpoint/synchronous.py b/pyrevolut/api/cards/endpoint/synchronous.py index 0e9716b..25cf9f6 100644 --- a/pyrevolut/api/cards/endpoint/synchronous.py +++ b/pyrevolut/api/cards/endpoint/synchronous.py @@ -1,6 +1,5 @@ from typing import Literal, Type from uuid import UUID -from decimal import Decimal from datetime import datetime from pydantic import BaseModel @@ -139,19 +138,19 @@ def create_card( label: str | None = None, accounts: list[UUID] | None = None, categories: list[EnumMerchantCategory] | None = None, - single_limit_amount: Decimal | None = None, + single_limit_amount: float | None = None, single_limit_currency: str | None = None, - day_limit_amount: Decimal | None = None, + day_limit_amount: float | None = None, day_limit_currency: str | None = None, - week_limit_amount: Decimal | None = None, + week_limit_amount: float | None = None, week_limit_currency: str | None = None, - month_limit_amount: Decimal | None = None, + month_limit_amount: float | None = None, month_limit_currency: str | None = None, - quarter_limit_amount: Decimal | None = None, + quarter_limit_amount: float | None = None, quarter_limit_currency: str | None = None, - year_limit_amount: Decimal | None = None, + year_limit_amount: float | None = None, year_limit_currency: str | None = None, - all_time_limit_amount: Decimal | None = None, + all_time_limit_amount: float | None = None, all_time_limit_currency: str | None = None, **kwargs, ) -> dict | CreateCard.Response: @@ -179,31 +178,31 @@ def create_card( The list of accounts to link to the card. If not specified, all accounts will be linked. categories : list[EnumMerchantCategory] | None The list of merchant categories to link to the card. If not specified, all categories will be linked. - single_limit_amount : Decimal | None + single_limit_amount : float | None The maximum amount for a single transaction. single_limit_currency : str | None The currency of the single transaction limit. - day_limit_amount : Decimal | None + day_limit_amount : float | None The maximum amount for transactions in a day. day_limit_currency : str | None The currency of the day limit. - week_limit_amount : Decimal | None + week_limit_amount : float | None The maximum amount for transactions in a week. week_limit_currency : str | None The currency of the week limit. - month_limit_amount : Decimal | None + month_limit_amount : float | None The maximum amount for transactions in a month. month_limit_currency : str | None The currency of the month limit. - quarter_limit_amount : Decimal | None + quarter_limit_amount : float | None The maximum amount for transactions in a quarter. quarter_limit_currency : str | None The currency of the quarter limit. - year_limit_amount : Decimal | None + year_limit_amount : float | None The maximum amount for transactions in a year. year_limit_currency : str | None The currency of the year limit. - all_time_limit_amount : Decimal | None + all_time_limit_amount : float | None The maximum amount for transactions in the card's lifetime. all_time_limit_currency : str | None The currency of the all-time limit. @@ -381,19 +380,19 @@ def update_card( card_id: UUID, label: str | None = None, categories: list[EnumMerchantCategory] | Literal["null"] | None = None, - single_limit_amount: Decimal | Literal["null"] | None = None, + single_limit_amount: float | Literal["null"] | None = None, single_limit_currency: str | Literal["null"] | None = None, - day_limit_amount: Decimal | Literal["null"] | None = None, + day_limit_amount: float | Literal["null"] | None = None, day_limit_currency: str | Literal["null"] | None = None, - week_limit_amount: Decimal | Literal["null"] | None = None, + week_limit_amount: float | Literal["null"] | None = None, week_limit_currency: str | Literal["null"] | None = None, - month_limit_amount: Decimal | Literal["null"] | None = None, + month_limit_amount: float | Literal["null"] | None = None, month_limit_currency: str | Literal["null"] | None = None, - quarter_limit_amount: Decimal | Literal["null"] | None = None, + quarter_limit_amount: float | Literal["null"] | None = None, quarter_limit_currency: str | Literal["null"] | None = None, - year_limit_amount: Decimal | Literal["null"] | None = None, + year_limit_amount: float | Literal["null"] | None = None, year_limit_currency: str | Literal["null"] | None = None, - all_time_limit_amount: Decimal | Literal["null"] | None = None, + all_time_limit_amount: float | Literal["null"] | None = None, all_time_limit_currency: str | Literal["null"] | None = None, **kwargs, ) -> dict | UpdateCardDetails.Response: @@ -410,43 +409,43 @@ def update_card( categories : list[EnumMerchantCategory] | Literal["null"] | None The list of merchant categories to link to the card. If set to 'null', all categories will be linked. - single_limit_amount : Decimal | Literal["null"] | None + single_limit_amount : float | Literal["null"] | None The maximum amount for a single transaction. If set to 'null', the limit will be removed. single_limit_currency : str | Literal["null"] | None The currency of the single transaction limit. If set to 'null', the limit will be removed. - day_limit_amount : Decimal | Literal["null"] | None + day_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a day. If set to 'null', the limit will be removed. day_limit_currency : str | Literal["null"] | None The currency of the day limit. If set to 'null', the limit will be removed. - week_limit_amount : Decimal | Literal["null"] | None + week_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a week. If set to 'null', the limit will be removed. week_limit_currency : str | Literal["null"] | None The currency of the week limit. If set to 'null', the limit will be removed. - month_limit_amount : Decimal | Literal["null"] | None + month_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a month. If set to 'null', the limit will be removed. month_limit_currency : str | Literal["null"] | None The currency of the month limit. If set to 'null', the limit will be removed. - quarter_limit_amount : Decimal | Literal["null"] | None + quarter_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a quarter. If set to 'null', the limit will be removed. quarter_limit_currency : str | Literal["null"] | None The currency of the quarter limit. If set to 'null', the limit will be removed. - year_limit_amount : Decimal | Literal["null"] | None + year_limit_amount : float | Literal["null"] | None The maximum amount for transactions in a year. If set to 'null', the limit will be removed. year_limit_currency : str | Literal["null"] | None The currency of the year limit. If set to 'null', the limit will be removed. - all_time_limit_amount : Decimal | Literal["null"] | None + all_time_limit_amount : float | Literal["null"] | None The maximum amount for transactions in the card's lifetime. If set to 'null', the limit will be removed. all_time_limit_currency : str | Literal["null"] | None @@ -575,7 +574,7 @@ def delete_card( def __process_limit_model( self, model: Type[BaseModel], - amount: Decimal | None, + amount: float | None, currency: str | None, ): """ diff --git a/pyrevolut/api/common/models/amount.py b/pyrevolut/api/common/models/amount.py index 15cf482..5d17986 100644 --- a/pyrevolut/api/common/models/amount.py +++ b/pyrevolut/api/common/models/amount.py @@ -1,12 +1,14 @@ from typing import Annotated -from decimal import Decimal -from pydantic import BaseModel +from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency class ModelBaseAmount(BaseModel): """Base model for amount""" - amount: Annotated[Decimal, "The value."] - currency: Annotated[Currency, "The currency, provided as a 3-letter ISO 4217 code."] + amount: Annotated[float, Field(description="The value.")] + currency: Annotated[ + Currency, + Field(description="The currency, provided as a 3-letter ISO 4217 code."), + ] diff --git a/pyrevolut/api/foreign_exchange/endpoint/asynchronous.py b/pyrevolut/api/foreign_exchange/endpoint/asynchronous.py index 28fd2f1..6b05e6b 100644 --- a/pyrevolut/api/foreign_exchange/endpoint/asynchronous.py +++ b/pyrevolut/api/foreign_exchange/endpoint/asynchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from pyrevolut.api.common import BaseEndpointAsync @@ -17,7 +16,7 @@ async def get_exchange_rate( self, from_currency: str, to_currency: str, - amount: Decimal | None = None, + amount: float | None = None, **kwargs, ) -> dict | GetExchangeRate.Response: """ @@ -29,7 +28,7 @@ async def get_exchange_rate( The currency that you exchange from in ISO 4217 format. to_currency : str The currency that you exchange to in ISO 4217 format. - amount : Decimal | None + amount : float | None The amount of the currency to exchange from. The default value is 1.00 if not provided. @@ -60,8 +59,8 @@ async def exchange_money( from_currency: str, to_account_id: UUID, to_currency: str, - from_amount: Decimal | None = None, - to_amount: Decimal | None = None, + from_amount: float | None = None, + to_amount: float | None = None, reference: str | None = None, **kwargs, ) -> dict | ExchangeMoney.Response: @@ -95,9 +94,9 @@ async def exchange_money( The ID of the account to receive exchanged currency into. to_currency : str The currency to buy in ISO 4217 format. - from_amount : Decimal | None + from_amount : float | None The amount of currency. Specify ONLY if you want to sell currency. - to_amount : Decimal | None + to_amount : float | None The amount of currency. Specify ONLY if you want to buy currency. reference : str | None The reference for the exchange transaction, provided by you. diff --git a/pyrevolut/api/foreign_exchange/endpoint/synchronous.py b/pyrevolut/api/foreign_exchange/endpoint/synchronous.py index 31235a2..55a1847 100644 --- a/pyrevolut/api/foreign_exchange/endpoint/synchronous.py +++ b/pyrevolut/api/foreign_exchange/endpoint/synchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from pyrevolut.api.common import BaseEndpointSync @@ -17,7 +16,7 @@ def get_exchange_rate( self, from_currency: str, to_currency: str, - amount: Decimal | None = None, + amount: float | None = None, **kwargs, ) -> dict | GetExchangeRate.Response: """ @@ -29,7 +28,7 @@ def get_exchange_rate( The currency that you exchange from in ISO 4217 format. to_currency : str The currency that you exchange to in ISO 4217 format. - amount : Decimal | None + amount : float | None The amount of the currency to exchange from. The default value is 1.00 if not provided. @@ -60,8 +59,8 @@ def exchange_money( from_currency: str, to_account_id: UUID, to_currency: str, - from_amount: Decimal | None = None, - to_amount: Decimal | None = None, + from_amount: float | None = None, + to_amount: float | None = None, reference: str | None = None, **kwargs, ) -> dict | ExchangeMoney.Response: @@ -95,9 +94,9 @@ def exchange_money( The ID of the account to receive exchanged currency into. to_currency : str The currency to buy in ISO 4217 format. - from_amount : Decimal | None + from_amount : float | None The amount of currency. Specify ONLY if you want to sell currency. - to_amount : Decimal | None + to_amount : float | None The amount of currency. Specify ONLY if you want to buy currency. reference : str | None The reference for the exchange transaction, provided by you. diff --git a/pyrevolut/api/foreign_exchange/get/get_exchange_rate.py b/pyrevolut/api/foreign_exchange/get/get_exchange_rate.py index aab48b0..0356aea 100644 --- a/pyrevolut/api/foreign_exchange/get/get_exchange_rate.py +++ b/pyrevolut/api/foreign_exchange/get/get_exchange_rate.py @@ -1,5 +1,4 @@ from typing import Annotated -from decimal import Decimal from pydantic import BaseModel, Field, ConfigDict from pydantic_extra_types.currency_code import Currency @@ -36,7 +35,7 @@ class Params(BaseModel): Field(description="The currency that you exchange to in ISO 4217 format."), ] amount: Annotated[ - Decimal | None, + float | None, Field( description="The amount of the currency to exchange from. The default value is 1.00." ), diff --git a/pyrevolut/api/foreign_exchange/post/exchange_money.py b/pyrevolut/api/foreign_exchange/post/exchange_money.py index cfb71af..394dc41 100644 --- a/pyrevolut/api/foreign_exchange/post/exchange_money.py +++ b/pyrevolut/api/foreign_exchange/post/exchange_money.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -# from decimal import Decimal from pydantic import BaseModel, Field, model_validator, ConfigDict from pydantic_extra_types.currency_code import Currency @@ -46,8 +45,6 @@ class ModelFrom(BaseModel): Currency, Field(description="The currency to sell in ISO 4217 format."), ] - # Originally Decimal | None but Revolut API fails when Decimal -> str is used - # So, we use float | None instead amount: Annotated[ float | None, Field( @@ -68,8 +65,6 @@ class ModelTo(BaseModel): Currency, Field(description="The currency to buy in ISO 4217 format."), ] - # Originally Decimal | None but Revolut API fails when Decimal -> str is used - # So, we use float | None instead amount: Annotated[ float | None, Field( diff --git a/pyrevolut/api/foreign_exchange/resources/foreign_exchange.py b/pyrevolut/api/foreign_exchange/resources/foreign_exchange.py index 21cea4e..ef5c319 100644 --- a/pyrevolut/api/foreign_exchange/resources/foreign_exchange.py +++ b/pyrevolut/api/foreign_exchange/resources/foreign_exchange.py @@ -1,5 +1,4 @@ from typing import Annotated -from decimal import Decimal from pydantic import BaseModel, Field, ConfigDict @@ -40,7 +39,7 @@ class ModelFee(ModelBaseAmount): from_: Annotated[ModelFrom, Field(alias="from", description="The money to sell.")] to: Annotated[ModelTo, Field(description="The money to receive.")] - rate: Annotated[Decimal, Field(description="The proposed exchange rate.")] + rate: Annotated[float, Field(description="The proposed exchange rate.")] fee: Annotated[ModelFee, Field(description="The expected fee for the transaction.")] rate_date: Annotated[ DateTime, diff --git a/pyrevolut/api/payment_drafts/endpoint/asynchronous.py b/pyrevolut/api/payment_drafts/endpoint/asynchronous.py index 1085997..df20918 100644 --- a/pyrevolut/api/payment_drafts/endpoint/asynchronous.py +++ b/pyrevolut/api/payment_drafts/endpoint/asynchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from datetime import date from pyrevolut.utils import Date @@ -86,7 +85,7 @@ async def create_payment_draft( counterparty_ids: list[UUID] = [], counterparty_account_ids: list[UUID | None] = [], counterparty_card_ids: list[UUID | None] = [], - amounts: list[Decimal] = [], + amounts: list[float] = [], currencies: list[str] = [], references: list[str] = [], title: str | None = None, @@ -110,7 +109,7 @@ async def create_payment_draft( The IDs of the counterparty cards. Each ID corresponds to a payment. If the counterparty has multiple payment methods available, use it to specify the card to which you want to send the money. Otherwise, use None. - amounts : list[Decimal] + amounts : list[float] The amounts of the payments. currencies : list[str] The ISO 4217 currency codes in upper case. diff --git a/pyrevolut/api/payment_drafts/endpoint/synchronous.py b/pyrevolut/api/payment_drafts/endpoint/synchronous.py index ad7526a..bd61c44 100644 --- a/pyrevolut/api/payment_drafts/endpoint/synchronous.py +++ b/pyrevolut/api/payment_drafts/endpoint/synchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from datetime import date from pyrevolut.utils import Date @@ -86,7 +85,7 @@ def create_payment_draft( counterparty_ids: list[UUID] = [], counterparty_account_ids: list[UUID | None] = [], counterparty_card_ids: list[UUID | None] = [], - amounts: list[Decimal] = [], + amounts: list[float] = [], currencies: list[str] = [], references: list[str] = [], title: str | None = None, @@ -110,7 +109,7 @@ def create_payment_draft( The IDs of the counterparty cards. Each ID corresponds to a payment. If the counterparty has multiple payment methods available, use it to specify the card to which you want to send the money. Otherwise, use None. - amounts : list[Decimal] + amounts : list[float] The amounts of the payments. currencies : list[str] The ISO 4217 currency codes in upper case. diff --git a/pyrevolut/api/payment_drafts/get/retrieve_payment_draft.py b/pyrevolut/api/payment_drafts/get/retrieve_payment_draft.py index b7f8f16..7b00dbe 100644 --- a/pyrevolut/api/payment_drafts/get/retrieve_payment_draft.py +++ b/pyrevolut/api/payment_drafts/get/retrieve_payment_draft.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field, ConfigDict from pydantic_extra_types.currency_code import Currency @@ -104,7 +103,7 @@ class ModelFee(ModelBaseAmount): Field(description="The target of the conversion."), ] rate: Annotated[ - Decimal | None, + float | None, Field(description="The exchange rate used for the conversion."), ] = None fee: Annotated[ diff --git a/pyrevolut/api/payment_drafts/post/create_payment_draft.py b/pyrevolut/api/payment_drafts/post/create_payment_draft.py index 2cbac0e..f1076a8 100644 --- a/pyrevolut/api/payment_drafts/post/create_payment_draft.py +++ b/pyrevolut/api/payment_drafts/post/create_payment_draft.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency @@ -81,7 +80,7 @@ class ModelReceiver(BaseModel): ), ] amount: Annotated[ - Decimal, + float, Field(description="The amount of the payment."), ] currency: Annotated[ diff --git a/pyrevolut/api/payout_links/endpoint/asynchronous.py b/pyrevolut/api/payout_links/endpoint/asynchronous.py index 7aaee00..054b105 100644 --- a/pyrevolut/api/payout_links/endpoint/asynchronous.py +++ b/pyrevolut/api/payout_links/endpoint/asynchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from datetime import datetime from pydantic_extra_types.pendulum_dt import Duration @@ -135,7 +134,7 @@ async def create_payout_link( counterparty_name: str, request_id: str, account_id: UUID, - amount: Decimal, + amount: float, currency: str, reference: str, payout_methods: list[EnumPayoutLinkPaymentMethod], @@ -166,7 +165,7 @@ async def create_payout_link( requests related to the same link. account_id : UUID The ID of the sender's account. - amount : Decimal + amount : float The amount of money to be sent. currency : str The currency of the amount to be sent. diff --git a/pyrevolut/api/payout_links/endpoint/synchronous.py b/pyrevolut/api/payout_links/endpoint/synchronous.py index 56d6c7d..977aae3 100644 --- a/pyrevolut/api/payout_links/endpoint/synchronous.py +++ b/pyrevolut/api/payout_links/endpoint/synchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from datetime import datetime from pydantic_extra_types.pendulum_dt import Duration @@ -135,7 +134,7 @@ def create_payout_link( counterparty_name: str, request_id: str, account_id: UUID, - amount: Decimal, + amount: float, currency: str, reference: str, payout_methods: list[EnumPayoutLinkPaymentMethod], @@ -166,7 +165,7 @@ def create_payout_link( requests related to the same link. account_id : UUID The ID of the sender's account. - amount : Decimal + amount : float The amount of money to be sent. currency : str The currency of the amount to be sent. diff --git a/pyrevolut/api/payout_links/post/create_payout_link.py b/pyrevolut/api/payout_links/post/create_payout_link.py index f863e96..4031c63 100644 --- a/pyrevolut/api/payout_links/post/create_payout_link.py +++ b/pyrevolut/api/payout_links/post/create_payout_link.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency @@ -75,7 +74,7 @@ class Body(BaseModel): ), ] amount: Annotated[ - Decimal, + float, Field( description=""" The amount of money to be transferred. diff --git a/pyrevolut/api/payout_links/resources/payout_link.py b/pyrevolut/api/payout_links/resources/payout_link.py index 571e8e7..bf58934 100644 --- a/pyrevolut/api/payout_links/resources/payout_link.py +++ b/pyrevolut/api/payout_links/resources/payout_link.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field, HttpUrl from pydantic_extra_types.currency_code import Currency @@ -116,7 +115,7 @@ class ResourcePayoutLink(BaseModel): ] account_id: Annotated[UUID, Field(description="The ID of the sender's account.")] amount: Annotated[ - Decimal, + float, Field( description=""" The amount of money to be transferred. diff --git a/pyrevolut/api/simulations/endpoint/asynchronous.py b/pyrevolut/api/simulations/endpoint/asynchronous.py index 502adaa..1f3e4b3 100644 --- a/pyrevolut/api/simulations/endpoint/asynchronous.py +++ b/pyrevolut/api/simulations/endpoint/asynchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from pyrevolut.exceptions import InvalidEnvironmentException from pyrevolut.api.common import ( @@ -24,7 +23,7 @@ class EndpointSimulationsAsync(BaseEndpointAsync): async def simulate_account_topup( self, account_id: UUID, - amount: Decimal, + amount: float, currency: str, reference: str | None = None, state: EnumTransactionState | None = None, @@ -40,7 +39,7 @@ async def simulate_account_topup( ---------- account_id : UUID The ID of the account that you want to top up. - amount : Decimal + amount : float The amount with which you want to top up the account. Must be <= 10000 currency : str The currency of the top-up amount. Must be a valid ISO 4217 currency code. diff --git a/pyrevolut/api/simulations/endpoint/synchronous.py b/pyrevolut/api/simulations/endpoint/synchronous.py index 9b12686..57182af 100644 --- a/pyrevolut/api/simulations/endpoint/synchronous.py +++ b/pyrevolut/api/simulations/endpoint/synchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from pyrevolut.exceptions import InvalidEnvironmentException from pyrevolut.api.common import ( @@ -24,7 +23,7 @@ class EndpointSimulationsSync(BaseEndpointSync): def simulate_account_topup( self, account_id: UUID, - amount: Decimal, + amount: float, currency: str, reference: str | None = None, state: EnumTransactionState | None = None, @@ -40,7 +39,7 @@ def simulate_account_topup( ---------- account_id : UUID The ID of the account that you want to top up. - amount : Decimal + amount : float The amount with which you want to top up the account. Must be <= 10000 currency : str The currency of the top-up amount. Must be a valid ISO 4217 currency code. diff --git a/pyrevolut/api/simulations/post/simulate_account_topup.py b/pyrevolut/api/simulations/post/simulate_account_topup.py index dbb9c10..fcb3a49 100644 --- a/pyrevolut/api/simulations/post/simulate_account_topup.py +++ b/pyrevolut/api/simulations/post/simulate_account_topup.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field, model_validator from pydantic_extra_types.currency_code import Currency @@ -29,7 +28,7 @@ class Body(BaseModel): Field(description="The ID of the account that you want to top up."), ] amount: Annotated[ - Decimal, + float, Field( description="The amount with which you want to top up the account. Must be <= 10000", gt=0, diff --git a/pyrevolut/api/transactions/resources/transaction.py b/pyrevolut/api/transactions/resources/transaction.py index 870c74b..8ea3cb2 100644 --- a/pyrevolut/api/transactions/resources/transaction.py +++ b/pyrevolut/api/transactions/resources/transaction.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency @@ -64,11 +63,11 @@ class ModelCounterparty(BaseModel): leg_id: Annotated[UUID, Field(description="The ID of the leg.")] amount: Annotated[ - Decimal, + float, Field(description="The amount of the transaction leg."), ] fee: Annotated[ - Decimal | None, + float | None, Field(description="The amount of the transaction leg fee."), ] = None currency: Annotated[ @@ -76,7 +75,7 @@ class ModelCounterparty(BaseModel): Field(description="ISO 4217 currency code in upper case."), ] bill_amount: Annotated[ - Decimal | None, + float | None, Field(description="The billing amount for cross-currency payments."), ] = None bill_currency: Annotated[ @@ -98,7 +97,7 @@ class ModelCounterparty(BaseModel): Field(description="The transaction leg purpose."), ] = None balance: Annotated[ - Decimal | None, + float | None, Field( description="The total balance of the account that the transaction is associated with." ), diff --git a/pyrevolut/api/transfers/endpoint/asynchronous.py b/pyrevolut/api/transfers/endpoint/asynchronous.py index dd2d91d..bd35148 100644 --- a/pyrevolut/api/transfers/endpoint/asynchronous.py +++ b/pyrevolut/api/transfers/endpoint/asynchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from pyrevolut.api.common import ( BaseEndpointAsync, @@ -59,7 +58,7 @@ async def create_transfer_to_another_account( request_id: str, account_id: UUID, counterparty_id: UUID, - amount: Decimal, + amount: float, currency: str, counterparty_account_id: UUID | None = None, counterparty_card_id: UUID | None = None, @@ -98,7 +97,7 @@ async def create_transfer_to_another_account( The ID of the account that you transfer the funds from. counterparty_id : UUID The ID of the receiving counterparty. - amount : Decimal + amount : float The amount of money to transfer. currency : str The currency of the transfer. @@ -164,7 +163,7 @@ async def move_money_between_accounts( request_id: str, source_account_id: UUID, target_account_id: UUID, - amount: Decimal, + amount: float, currency: str, reference: str | None = None, **kwargs, @@ -186,7 +185,7 @@ async def move_money_between_accounts( The ID of the source account that you transfer the funds from. target_account_id : UUID The ID of the target account that you transfer the funds to. - amount : Decimal + amount : float The amount of the funds to be transferred. currency : str The ISO 4217 currency of the funds to be transferred. diff --git a/pyrevolut/api/transfers/endpoint/synchronous.py b/pyrevolut/api/transfers/endpoint/synchronous.py index 98d61fb..f21232e 100644 --- a/pyrevolut/api/transfers/endpoint/synchronous.py +++ b/pyrevolut/api/transfers/endpoint/synchronous.py @@ -1,5 +1,4 @@ from uuid import UUID -from decimal import Decimal from pyrevolut.api.common import ( BaseEndpointSync, @@ -59,7 +58,7 @@ def create_transfer_to_another_account( request_id: str, account_id: UUID, counterparty_id: UUID, - amount: Decimal, + amount: float, currency: str, counterparty_account_id: UUID | None = None, counterparty_card_id: UUID | None = None, @@ -98,7 +97,7 @@ def create_transfer_to_another_account( The ID of the account that you transfer the funds from. counterparty_id : UUID The ID of the receiving counterparty. - amount : Decimal + amount : float The amount of money to transfer. currency : str The currency of the transfer. @@ -164,7 +163,7 @@ def move_money_between_accounts( request_id: str, source_account_id: UUID, target_account_id: UUID, - amount: Decimal, + amount: float, currency: str, reference: str | None = None, **kwargs, @@ -186,7 +185,7 @@ def move_money_between_accounts( The ID of the source account that you transfer the funds from. target_account_id : UUID The ID of the target account that you transfer the funds to. - amount : Decimal + amount : float The amount of the funds to be transferred. currency : str The ISO 4217 currency of the funds to be transferred. diff --git a/pyrevolut/api/transfers/post/create_transfer_to_another_account.py b/pyrevolut/api/transfers/post/create_transfer_to_another_account.py index b66be9c..a6bfa1e 100644 --- a/pyrevolut/api/transfers/post/create_transfer_to_another_account.py +++ b/pyrevolut/api/transfers/post/create_transfer_to_another_account.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency @@ -103,7 +102,7 @@ class ModelReceiver(BaseModel): ), ] amount: Annotated[ - Decimal, + float, Field( description="The amount of the funds to be transferred.", gt=0, diff --git a/pyrevolut/api/transfers/post/move_money_between_accounts.py b/pyrevolut/api/transfers/post/move_money_between_accounts.py index 0b6f899..8821771 100644 --- a/pyrevolut/api/transfers/post/move_money_between_accounts.py +++ b/pyrevolut/api/transfers/post/move_money_between_accounts.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency @@ -48,7 +47,7 @@ class Body(BaseModel): ), ] amount: Annotated[ - Decimal, + float, Field( description="The amount of the funds to be transferred.", gt=0, diff --git a/pyrevolut/api/webhooks/resources/transaction_created.py b/pyrevolut/api/webhooks/resources/transaction_created.py index dc19590..ed74e2e 100644 --- a/pyrevolut/api/webhooks/resources/transaction_created.py +++ b/pyrevolut/api/webhooks/resources/transaction_created.py @@ -1,6 +1,5 @@ from typing import Annotated from uuid import UUID -from decimal import Decimal from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency @@ -57,11 +56,11 @@ class ModelCounterparty(BaseModel): Field(description="The counterparty of the transaction leg."), ] = None amount: Annotated[ - Decimal, + float, Field(description="The amount of the transaction leg."), ] fee: Annotated[ - Decimal | None, + float | None, Field(description="The amount of the transaction leg fee."), ] = None currency: Annotated[ @@ -69,7 +68,7 @@ class ModelCounterparty(BaseModel): Field(description="ISO 4217 currency code in upper case."), ] bill_amount: Annotated[ - Decimal | None, + float | None, Field(description="The billing amount for cross-currency payments."), ] = None bill_currency: Annotated[ @@ -81,7 +80,7 @@ class ModelCounterparty(BaseModel): Field(description="The transaction leg purpose."), ] = None balance: Annotated[ - Decimal | None, + float | None, Field( description="The total balance of the account that the transaction is associated with." ), diff --git a/pyrevolut/client/base.py b/pyrevolut/client/base.py index 274704f..c1e8d41 100644 --- a/pyrevolut/client/base.py +++ b/pyrevolut/client/base.py @@ -65,7 +65,7 @@ def __init__( The raw response will be returned If "dict": The response will be the dictionary representation of the Pydantic model. - So it will have Decimals, UUIDs, etc instead of the raw string values. + So it will have UUIDs, pendulum DateTimes, etc instead of the raw string values. If "model": The response will be a Pydantic model containing all processed response data. error_response : Literal["raw", "raise", "dict", "model"], optional @@ -125,7 +125,7 @@ def process_response( The raw response will be returned If "dict": The response will be the dictionary representation of the Pydantic model. - So it will have Decimals, UUIDs, etc instead of the raw string values. + So it will have UUIDs, pendulum DateTimes, etc instead of the raw string values. If "model": The response will be a Pydantic model containing all processed response data. If None: diff --git a/tests/conftest.py b/tests/conftest.py index ab7ecba..799c0aa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,6 @@ import asyncio import time import random -from decimal import Decimal import pytest import pytest_asyncio @@ -90,10 +89,10 @@ def sync_client(base_sync_client: Client): accounts = base_sync_client.Accounts.get_all_accounts() time.sleep(random.randint(1, 3)) for account in accounts: - if account["balance"] == Decimal("0"): + if account["balance"] == 0.0: base_sync_client.Simulations.simulate_account_topup( account_id=account["id"], - amount=Decimal("100.00"), + amount=100.0, currency=account["currency"], reference="Sugar Daddy <3", state=EnumTransactionState.COMPLETED, @@ -128,10 +127,10 @@ async def async_client(base_async_client: AsyncClient): accounts = await base_async_client.Accounts.get_all_accounts() await asyncio.sleep(random.randint(1, 3)) for account in accounts: - if account["balance"] == Decimal("0"): + if account["balance"] == 0.0: await base_async_client.Simulations.simulate_account_topup( account_id=account["id"], - amount=Decimal("100.00"), + amount=100.0, currency=account["currency"], reference="Sugar Daddy <3", state=EnumTransactionState.COMPLETED, diff --git a/tests/test_foreign_exchange.py b/tests/test_foreign_exchange.py index 25d5b2c..857cc81 100644 --- a/tests/test_foreign_exchange.py +++ b/tests/test_foreign_exchange.py @@ -1,7 +1,6 @@ import time import asyncio from uuid import uuid4 -from decimal import Decimal import pytest import random @@ -47,7 +46,7 @@ def test_sync_exchange_money(sync_client: Client): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) gbp_balance = gbp_account["balance"] eur_account = next( @@ -55,7 +54,7 @@ def test_sync_exchange_money(sync_client: Client): for account in accounts if account["currency"] == "EUR" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) eur_balance = eur_account["balance"] @@ -66,7 +65,7 @@ def test_sync_exchange_money(sync_client: Client): from_currency="EUR", to_account_id=gbp_account["id"], to_currency="GBP", - from_amount=Decimal("1"), + from_amount=1.0, to_amount=None, reference="PyRevolut Test", ) @@ -81,21 +80,21 @@ def test_sync_exchange_money(sync_client: Client): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) eur_balance2 = next( account["balance"] for account in accounts if account["currency"] == "EUR" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) assert gbp_balance2 > gbp_balance - assert eur_balance2 == eur_balance - Decimal("1") + assert eur_balance2 == eur_balance - 1.0 with pytest.raises( InternalRevolutError, - match="Oops! An error occurred while processing your request. It has been logged for further investigation.", + match="Oops! An error occurred while processing your request.", ): # Exchange 1 EUR from GBP to EUR response = sync_client.ForeignExchange.exchange_money( @@ -105,7 +104,7 @@ def test_sync_exchange_money(sync_client: Client): to_account_id=eur_account["id"], to_currency="EUR", from_amount=None, - to_amount=Decimal("1"), + to_amount=1.0, reference="PyRevolut Test", ) time.sleep(random.randint(1, 3)) @@ -170,7 +169,7 @@ async def test_async_exchange_money(async_client: AsyncClient): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) gbp_balance = gbp_account["balance"] eur_account = next( @@ -178,7 +177,7 @@ async def test_async_exchange_money(async_client: AsyncClient): for account in accounts if account["currency"] == "EUR" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) eur_balance = eur_account["balance"] @@ -189,7 +188,7 @@ async def test_async_exchange_money(async_client: AsyncClient): from_currency="EUR", to_account_id=gbp_account["id"], to_currency="GBP", - from_amount=Decimal("1"), + from_amount=1.0, to_amount=None, reference="PyRevolut Test", ) @@ -204,21 +203,21 @@ async def test_async_exchange_money(async_client: AsyncClient): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) eur_balance2 = next( account["balance"] for account in accounts if account["currency"] == "EUR" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) assert gbp_balance2 > gbp_balance - assert eur_balance2 == eur_balance - Decimal("1") + assert eur_balance2 == eur_balance - 1.0 with pytest.raises( InternalRevolutError, - match="Oops! An error occurred while processing your request. It has been logged for further investigation.", + match="Oops! An error occurred while processing your request.", ): # Exchange 1 EUR from GBP to EUR response = await async_client.ForeignExchange.exchange_money( @@ -228,7 +227,7 @@ async def test_async_exchange_money(async_client: AsyncClient): to_account_id=eur_account["id"], to_currency="EUR", from_amount=None, - to_amount=Decimal("1"), + to_amount=1.0, reference="PyRevolut Test", ) await asyncio.sleep(random.randint(1, 3)) diff --git a/tests/test_payment_drafts.py b/tests/test_payment_drafts.py index a554dd7..19d418f 100644 --- a/tests/test_payment_drafts.py +++ b/tests/test_payment_drafts.py @@ -1,6 +1,5 @@ import time import asyncio -from decimal import Decimal import pytest import random @@ -50,7 +49,7 @@ def test_sync_create_delete_payment_draft(sync_client: Client): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) # Get recipients @@ -72,7 +71,7 @@ def test_sync_create_delete_payment_draft(sync_client: Client): counterparty_ids=[recipient["id"]], counterparty_account_ids=[None], counterparty_card_ids=[None], - amounts=[Decimal("1.00")], + amounts=[1.0], currencies=["GBP"], references=["test"], title="Test payment draft", @@ -129,7 +128,7 @@ async def test_async_create_delete_payment_draft(async_client: Client): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) # Get recipients @@ -151,7 +150,7 @@ async def test_async_create_delete_payment_draft(async_client: Client): counterparty_ids=[recipient["id"]], counterparty_account_ids=[None], counterparty_card_ids=[None], - amounts=[Decimal("1.00")], + amounts=[1.0], currencies=["GBP"], references=["test"], title="Test payment draft", diff --git a/tests/test_payout_links.py b/tests/test_payout_links.py index 6f4e1f7..a8f5108 100644 --- a/tests/test_payout_links.py +++ b/tests/test_payout_links.py @@ -1,6 +1,5 @@ import time import asyncio -from decimal import Decimal from uuid import uuid4 import pytest import random @@ -63,7 +62,7 @@ def test_sync_create_cancel_payout_link(sync_client: Client): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) # Create a payout link @@ -71,7 +70,7 @@ def test_sync_create_cancel_payout_link(sync_client: Client): counterparty_name="John Doe", request_id=str(uuid4()), account_id=gbp_account["id"], - amount=Decimal("1.00"), + amount=1.0, currency="GBP", reference="test payout link", payout_methods=[ @@ -158,7 +157,7 @@ async def test_async_create_cancel_payout_link(async_client: Client): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) # Create a payout link @@ -166,7 +165,7 @@ async def test_async_create_cancel_payout_link(async_client: Client): counterparty_name="John Doe", request_id=str(uuid4()), account_id=gbp_account["id"], - amount=Decimal("1.00"), + amount=1.0, currency="GBP", reference="test payout link", payout_methods=[ diff --git a/tests/test_simulations.py b/tests/test_simulations.py index ee00b5c..68eee9b 100644 --- a/tests/test_simulations.py +++ b/tests/test_simulations.py @@ -1,7 +1,6 @@ import time import asyncio from uuid import uuid4 -from decimal import Decimal import pytest import random @@ -38,7 +37,7 @@ def test_sync_simulate_account_topup(sync_client: Client): # Simulate a top-up of the GBP account response = sync_client.Simulations.simulate_account_topup( account_id=gbp_account["id"], - amount=Decimal("1.00"), + amount=1.0, currency="GBP", reference="Sugar Daddy <3", state=EnumTransactionState.COMPLETED, @@ -49,12 +48,12 @@ def test_sync_simulate_account_topup(sync_client: Client): # Get the GBP account by ID account = sync_client.Accounts.get_account(account_id=gbp_account["id"]) time.sleep(random.randint(1, 3)) - assert account["balance"] == gbp_account["balance"] + Decimal("1.00") + assert account["balance"] == gbp_account["balance"] + 1.0 # Simulate a top-up of the EUR account response = sync_client.Simulations.simulate_account_topup( account_id=eur_account["id"], - amount=Decimal("1.00"), + amount=1.0, currency="EUR", reference="Sugar Daddy <3", state=EnumTransactionState.COMPLETED, @@ -64,7 +63,7 @@ def test_sync_simulate_account_topup(sync_client: Client): # Get the EUR account by ID account = sync_client.Accounts.get_account(account_id=eur_account["id"]) time.sleep(random.randint(1, 3)) - assert account["balance"] == eur_account["balance"] + Decimal("1.00") + assert account["balance"] == eur_account["balance"] + 1.0 def test_sync_simulate_transfer_state_update(sync_client: Client): @@ -85,10 +84,10 @@ def test_sync_simulate_transfer_state_update(sync_client: Client): eur_balance = eur_account["balance"] # If there is no EUR balance, simulate a top up - if eur_balance < Decimal("1"): + if eur_balance < 1.0: response = sync_client.Simulations.simulate_account_topup( account_id=eur_account["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", reference="PyRevolut Test", state=EnumTransactionState.COMPLETED, @@ -120,7 +119,7 @@ def test_sync_simulate_transfer_state_update(sync_client: Client): request_id=str(uuid4()), account_id=eur_account["id"], counterparty_id=eur_counterparty["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", counterparty_account_id=eur_counterparty_account["id"], reference="PyRevolut Test", @@ -132,7 +131,7 @@ def test_sync_simulate_transfer_state_update(sync_client: Client): # Check balance account = sync_client.Accounts.get_account(account_id=eur_account["id"]) time.sleep(random.randint(1, 3)) - assert account["balance"] == eur_balance - Decimal("1") + assert account["balance"] == eur_balance - 1.0 # Decline the transfer response = sync_client.Simulations.simulate_transfer_state_update( @@ -173,7 +172,7 @@ async def test_async_simulate_account_topup(async_client: Client): # Simulate a top-up of the GBP account response = await async_client.Simulations.simulate_account_topup( account_id=gbp_account["id"], - amount=Decimal("1.00"), + amount=1.0, currency="GBP", reference="Sugar Daddy <3", state=EnumTransactionState.COMPLETED, @@ -184,12 +183,12 @@ async def test_async_simulate_account_topup(async_client: Client): # Get the GBP account by ID account = await async_client.Accounts.get_account(account_id=gbp_account["id"]) await asyncio.sleep(random.randint(1, 3)) - assert account["balance"] == gbp_account["balance"] + Decimal("1.00") + assert account["balance"] == gbp_account["balance"] + 1.0 # Simulate a top-up of the EUR account response = await async_client.Simulations.simulate_account_topup( account_id=eur_account["id"], - amount=Decimal("1.00"), + amount=1.0, currency="EUR", reference="Sugar Daddy <3", state=EnumTransactionState.COMPLETED, @@ -198,7 +197,7 @@ async def test_async_simulate_account_topup(async_client: Client): # Get the EUR account by ID account = await async_client.Accounts.get_account(account_id=eur_account["id"]) await asyncio.sleep(random.randint(1, 3)) - assert account["balance"] == eur_account["balance"] + Decimal("1.00") + assert account["balance"] == eur_account["balance"] + 1.0 @pytest.mark.asyncio @@ -220,10 +219,10 @@ async def test_async_simulate_transfer_state_update(async_client: Client): eur_balance = eur_account["balance"] # If there is no EUR balance, simulate a top up - if eur_balance < Decimal("1"): + if eur_balance < 1.0: response = await async_client.Simulations.simulate_account_topup( account_id=eur_account["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", reference="PyRevolut Test", state=EnumTransactionState.COMPLETED, @@ -255,7 +254,7 @@ async def test_async_simulate_transfer_state_update(async_client: Client): request_id=str(uuid4()), account_id=eur_account["id"], counterparty_id=eur_counterparty["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", counterparty_account_id=eur_counterparty_account["id"], reference="PyRevolut Test", @@ -267,7 +266,7 @@ async def test_async_simulate_transfer_state_update(async_client: Client): # Check balance account = await async_client.Accounts.get_account(account_id=eur_account["id"]) await asyncio.sleep(random.randint(1, 3)) - assert account["balance"] == eur_balance - Decimal("1") + assert account["balance"] == eur_balance - 1.0 # Decline the transfer response = await async_client.Simulations.simulate_transfer_state_update( diff --git a/tests/test_transfers.py b/tests/test_transfers.py index cedfb88..cdf5916 100644 --- a/tests/test_transfers.py +++ b/tests/test_transfers.py @@ -1,7 +1,6 @@ import time import asyncio from uuid import uuid4 -from decimal import Decimal import random import pytest @@ -38,7 +37,7 @@ def test_sync_move_money_between_accounts(sync_client: Client): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) gbp_balance1 = gbp_account1["balance"] gbp_account2 = next( @@ -55,7 +54,7 @@ def test_sync_move_money_between_accounts(sync_client: Client): request_id=str(uuid4()), source_account_id=gbp_account1["id"], target_account_id=gbp_account2["id"], - amount=Decimal("1"), + amount=1.0, currency="GBP", reference="PyRevolut Test", ) @@ -75,15 +74,15 @@ def test_sync_move_money_between_accounts(sync_client: Client): for account in accounts if account["id"] == gbp_account2["id"] ) - assert gbp_balance2_new == gbp_balance2 + Decimal("1") - assert gbp_balance1_new == gbp_balance1 - Decimal("1") + assert gbp_balance2_new == gbp_balance2 + 1.0 + assert gbp_balance1_new == gbp_balance1 - 1.0 # Move 1 GBP from Account 2 to Account 1 response = sync_client.Transfers.move_money_between_accounts( request_id=str(uuid4()), source_account_id=gbp_account2["id"], target_account_id=gbp_account1["id"], - amount=Decimal("1"), + amount=1.0, currency="GBP", reference="PyRevolut Test", ) @@ -135,10 +134,10 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): gbp_balance = gbp_account["balance"] # If there is no EUR balance, simulate a top up - if eur_balance < Decimal("1"): + if eur_balance < 1.0: response = sync_client.Simulations.simulate_account_topup( account_id=eur_account["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", reference="PyRevolut Test", state=EnumTransactionState.COMPLETED, @@ -147,10 +146,10 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): assert response["state"] == EnumTransactionState.COMPLETED # If there is no GBP balance, simulate a top up - if gbp_balance < Decimal("1"): + if gbp_balance < 1.0: response = sync_client.Simulations.simulate_account_topup( account_id=gbp_account["id"], - amount=Decimal("1"), + amount=1.0, currency="GBP", reference="PyRevolut Test", state=EnumTransactionState.COMPLETED, @@ -182,7 +181,7 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): request_id=str(uuid4()), account_id=eur_account["id"], counterparty_id=eur_counterparty["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", counterparty_account_id=eur_counterparty_account["id"], reference="PyRevolut Test", @@ -194,7 +193,7 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): # Check balance account = sync_client.Accounts.get_account(account_id=eur_account["id"]) time.sleep(random.randint(1, 3)) - assert account["balance"] == eur_balance - Decimal("1") + assert account["balance"] == eur_balance - 1.0 # Complete the transfer via simulation response = sync_client.Simulations.simulate_transfer_state_update( @@ -209,7 +208,7 @@ def test_sync_create_transfer_to_another_account(sync_client: Client): request_id=str(uuid4()), account_id=gbp_account["id"], counterparty_id=eur_counterparty["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", counterparty_account_id=eur_counterparty_account["id"], reference="PyRevolut Test", @@ -257,7 +256,7 @@ async def test_async_move_money_between_accounts(async_client: Client): for account in accounts if account["currency"] == "GBP" and account["state"] == EnumAccountState.ACTIVE - and account["balance"] > Decimal("0") + and account["balance"] > 0.0 ) gbp_balance1 = gbp_account1["balance"] gbp_account2 = next( @@ -274,7 +273,7 @@ async def test_async_move_money_between_accounts(async_client: Client): request_id=str(uuid4()), source_account_id=gbp_account1["id"], target_account_id=gbp_account2["id"], - amount=Decimal("1"), + amount=1.0, currency="GBP", reference="PyRevolut Test", ) @@ -294,15 +293,15 @@ async def test_async_move_money_between_accounts(async_client: Client): for account in accounts if account["id"] == gbp_account2["id"] ) - assert gbp_balance2_new == gbp_balance2 + Decimal("1") - assert gbp_balance1_new == gbp_balance1 - Decimal("1") + assert gbp_balance2_new == gbp_balance2 + 1.0 + assert gbp_balance1_new == gbp_balance1 - 1.0 # Move 1 GBP from Account 2 to Account 1 response = await async_client.Transfers.move_money_between_accounts( request_id=str(uuid4()), source_account_id=gbp_account2["id"], target_account_id=gbp_account1["id"], - amount=Decimal("1"), + amount=1.0, currency="GBP", reference="PyRevolut Test", ) @@ -355,10 +354,10 @@ async def test_async_create_transfer_to_another_account(async_client: Client): gbp_balance = gbp_account["balance"] # If there is no EUR balance, simulate a top up - if eur_balance < Decimal("1"): + if eur_balance < 1.0: response = await async_client.Simulations.simulate_account_topup( account_id=eur_account["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", reference="PyRevolut Test", state=EnumTransactionState.COMPLETED, @@ -367,10 +366,10 @@ async def test_async_create_transfer_to_another_account(async_client: Client): assert response["state"] == EnumTransactionState.COMPLETED # If there is no GBP balance, simulate a top up - if gbp_balance < Decimal("1"): + if gbp_balance < 1.0: response = await async_client.Simulations.simulate_account_topup( account_id=gbp_account["id"], - amount=Decimal("1"), + amount=1.0, currency="GBP", reference="PyRevolut Test", state=EnumTransactionState.COMPLETED, @@ -402,7 +401,7 @@ async def test_async_create_transfer_to_another_account(async_client: Client): request_id=str(uuid4()), account_id=eur_account["id"], counterparty_id=eur_counterparty["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", counterparty_account_id=eur_counterparty_account["id"], reference="PyRevolut Test", @@ -414,7 +413,7 @@ async def test_async_create_transfer_to_another_account(async_client: Client): # Check balance account = await async_client.Accounts.get_account(account_id=eur_account["id"]) await asyncio.sleep(random.randint(1, 3)) - assert account["balance"] == eur_balance - Decimal("1") + assert account["balance"] == eur_balance - 1.0 # Complete the transfer via simulation response = await async_client.Simulations.simulate_transfer_state_update( @@ -429,7 +428,7 @@ async def test_async_create_transfer_to_another_account(async_client: Client): request_id=str(uuid4()), account_id=gbp_account["id"], counterparty_id=eur_counterparty["id"], - amount=Decimal("1"), + amount=1.0, currency="EUR", counterparty_account_id=eur_counterparty_account["id"], reference="PyRevolut Test", From 7bc2279ad6aa0bd5e4fc617ad3fe288ade33e6f2 Mon Sep 17 00:00:00 2001 From: Trevor Visser Date: Sun, 19 May 2024 18:49:18 +0200 Subject: [PATCH 3/3] build: updated version dependencies --- poetry.lock | 79 ++++++++++++++++++++++---------------------------- pyproject.toml | 2 +- 2 files changed, 36 insertions(+), 45 deletions(-) diff --git a/poetry.lock b/poetry.lock index a693804..b9023e3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -567,56 +567,47 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "42.0.7" +version = "41.0.7" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"}, - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"}, - {file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"}, - {file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"}, - {file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"}, - {file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"}, - {file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"}, - {file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"}, -] - -[package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, + {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, + {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, + {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, +] + +[package.dependencies] +cffi = ">=1.12" [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] nox = ["nox"] -pep8test = ["check-sdist", "click", "mypy", "ruff"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -2737,13 +2728,13 @@ tests = ["pytest", "pytest-cov"] [[package]] name = "textual" -version = "0.61.0" +version = "0.61.1" description = "Modern Text User Interface framework" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "textual-0.61.0-py3-none-any.whl", hash = "sha256:176ac3aa5427fc076492d16afd20ea5c508605c2826cd176c8f5ac2589a1ee46"}, - {file = "textual-0.61.0.tar.gz", hash = "sha256:91c83a659da40b227eced4fa749026a236b493cc5911a9bedd990ad5f0786be2"}, + {file = "textual-0.61.1-py3-none-any.whl", hash = "sha256:58ef207424eb1015b85ca68abebf1a3c7b5cec108eec0d6a110f2aac9bc4d74f"}, + {file = "textual-0.61.1.tar.gz", hash = "sha256:8f1092f0db58f5214c0de1f8174ecf9db08356e30d0acca69a8df9a183a29f6c"}, ] [package.dependencies] @@ -2999,4 +2990,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "0d9f9a1906db0de7bbb91dca2b6496a04ddb1fcdcfc7cb0a3392f42fecce718c" +content-hash = "35ad60d342f8bc6352ce61807d4bc9fd9a8051b4159162799f0fdd20ad036c2b" diff --git a/pyproject.toml b/pyproject.toml index f873b60..234e14c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ pycountry = "^23.12.11" phonenumbers = "^8.13.36" pendulum = "^3.0.0" pyjwt = { extras = ["crypto"], version = "^2.8.0" } -cryptography = "^42.0.7" +cryptography = "^41.0.3" authlib = "^1.3.0" typer = "^0.12.3"