diff --git a/src/aleph/sdk/client/http.py b/src/aleph/sdk/client/http.py index 0ce33a7a..c1facba1 100644 --- a/src/aleph/sdk/client/http.py +++ b/src/aleph/sdk/client/http.py @@ -531,7 +531,10 @@ async def get_estimated_price( try: resp.raise_for_status() response_json = await resp.json() + cost = response_json.get("cost", None) + return PriceResponse( + cost=cost, required_tokens=response_json["required_tokens"], payment_type=response_json["payment_type"], ) @@ -543,8 +546,12 @@ async def get_program_price(self, item_hash: str) -> PriceResponse: try: resp.raise_for_status() response_json = await resp.json() + cost = response_json.get("cost", None) + required_tokens = response_json["required_tokens"] + return PriceResponse( - required_tokens=response_json["required_tokens"], + required_tokens=required_tokens, + cost=cost, payment_type=response_json["payment_type"], ) except aiohttp.ClientResponseError as e: diff --git a/src/aleph/sdk/client/services/crn.py b/src/aleph/sdk/client/services/crn.py index e8d57c8c..82cec51b 100644 --- a/src/aleph/sdk/client/services/crn.py +++ b/src/aleph/sdk/client/services/crn.py @@ -230,9 +230,8 @@ async def get_crns_list(self, only_active: bool = True) -> CrnList: dict The parsed JSON response from /crns.json. """ - # We want filter_inactive = (not only_active) # Convert bool to string for the query parameter - filter_inactive_str = str(not only_active).lower() + filter_inactive_str = str(only_active).lower() params = {"filter_inactive": filter_inactive_str} # Create a new session for external domain requests diff --git a/src/aleph/sdk/query/responses.py b/src/aleph/sdk/query/responses.py index b5958d47..6efade14 100644 --- a/src/aleph/sdk/query/responses.py +++ b/src/aleph/sdk/query/responses.py @@ -79,7 +79,8 @@ class MessagesResponse(PaginationResponse): class PriceResponse(BaseModel): """Response from an aleph.im node API on the path /api/v0/price/{item_hash}""" - required_tokens: float + required_tokens: Decimal + cost: Optional[str] = None payment_type: str diff --git a/src/aleph/sdk/types.py b/src/aleph/sdk/types.py index e76aedbc..b839a14b 100644 --- a/src/aleph/sdk/types.py +++ b/src/aleph/sdk/types.py @@ -309,7 +309,7 @@ class Ports(BaseModel): ports: Dict[int, PortFlags] -AllForwarders = RootModel[Dict[ItemHash, Ports]] +AllForwarders = RootModel[Dict[ItemHash, Optional[Ports]]] class DictLikeModel(BaseModel): diff --git a/tests/unit/test_price.py b/tests/unit/test_price.py index e60680f8..f2759193 100644 --- a/tests/unit/test_price.py +++ b/tests/unit/test_price.py @@ -1,3 +1,5 @@ +from decimal import Decimal + import pytest from aleph.sdk.exceptions import InvalidHashError @@ -21,6 +23,56 @@ async def test_get_program_price_valid(): assert response == expected +@pytest.mark.asyncio +async def test_get_program_price_cost_and_required_token(): + """ + Test that the get_program_price method returns the correct PriceResponse + when + 1 ) cost & required_token is here (priority to cost) who is a string that convert to decimal + 2 ) When only required_token is here who is a float that now would be to be convert to decimal + """ + # Case 1 + expected = { + "required_tokens": 0.001527777777777778, + "cost": "0.001527777777777777", + "payment_type": "credit", + } + + # Case 2 + expected_old = { + "required_tokens": 0.001527777777777778, + "payment_type": "credit", + } + + # Expected model using the cost field as the source of truth + expected_model = PriceResponse( + required_tokens=Decimal("0.001527777777777778"), + cost=expected["cost"], + payment_type=expected["payment_type"], + ) + + # Expected model for the old format + expected_model_old = PriceResponse( + required_tokens=Decimal(str(expected_old["required_tokens"])), + payment_type=expected_old["payment_type"], + ) + + mock_session = make_mock_get_session(expected) + mock_session_old = make_mock_get_session(expected_old) + + async with mock_session: + response = await mock_session.get_program_price("cacacacacacaca") + assert str(response.required_tokens) == str(expected_model.required_tokens) + assert response.cost == expected_model.cost + assert response.payment_type == expected_model.payment_type + + async with mock_session_old: + response = await mock_session_old.get_program_price("cacacacacacaca") + assert str(response.required_tokens) == str(expected_model_old.required_tokens) + assert response.cost == expected_model_old.cost + assert response.payment_type == expected_model_old.payment_type + + @pytest.mark.asyncio async def test_get_program_price_invalid(): """