Skip to content

Commit 2978646

Browse files
committed
lint3
1 parent 1202f73 commit 2978646

5 files changed

Lines changed: 63 additions & 10 deletions

File tree

packages/node/tests/functional_tests/test_accounts_CRUD_operations.py

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import octobot_node.scheduler.tasks as scheduler_tasks
2020
import octobot_node.scheduler.user_actions.user_actions_executor.util.account_state_updater as account_state_updater_module
2121
import octobot_protocol.models as protocol_models
22+
import octobot_trading.enums as trading_enums
2223
import octobot_trading.errors as trading_errors
2324
import octobot_trading.exchanges.connectors.ccxt.ccxt_connector as ccxt_connector_module
2425

@@ -30,6 +31,16 @@
3031
_WORKFLOW_RESULT_TIMEOUT_SECONDS = 120.0
3132
_USER_ACTION_LIST_POLL_TIMEOUT_SECONDS = 15.0
3233

34+
_FUNCTIONAL_USDT_HOLDINGS = 1000.0
35+
_FUNCTIONAL_BTC_HOLDINGS = 0.5
36+
_FUNCTIONAL_ETH_HOLDINGS = 2.0
37+
_FUNCTIONAL_BTC_USDT_CLOSE = 50000.0
38+
_EXPECTED_PORTFOLIO_UNIT = "USDT"
39+
_EXPECTED_USDT_VALUE = _FUNCTIONAL_USDT_HOLDINGS
40+
_EXPECTED_BTC_VALUE = _FUNCTIONAL_BTC_HOLDINGS * _FUNCTIONAL_BTC_USDT_CLOSE
41+
_EXPECTED_ETH_VALUE = 0.0
42+
_EXPECTED_PORTFOLIO_TOTAL = _EXPECTED_USDT_VALUE + _EXPECTED_BTC_VALUE + _EXPECTED_ETH_VALUE
43+
3344
_REAL_UPDATE_ACCOUNT_STATE = account_state_updater_module.update_account_state
3445

3546

@@ -68,14 +79,29 @@ async def _stub_load_symbol_markets_no_network(self, reload=False, market_filter
6879
async def _stub_get_balance_no_network(self, **kwargs):
6980
return {
7081
"USDT": {
71-
commons_constants.PORTFOLIO_TOTAL: 1000.0,
72-
commons_constants.PORTFOLIO_AVAILABLE: 1000.0,
73-
}
82+
commons_constants.PORTFOLIO_TOTAL: _FUNCTIONAL_USDT_HOLDINGS,
83+
commons_constants.PORTFOLIO_AVAILABLE: _FUNCTIONAL_USDT_HOLDINGS,
84+
},
85+
"BTC": {
86+
commons_constants.PORTFOLIO_TOTAL: _FUNCTIONAL_BTC_HOLDINGS,
87+
commons_constants.PORTFOLIO_AVAILABLE: _FUNCTIONAL_BTC_HOLDINGS,
88+
},
89+
"ETH": {
90+
commons_constants.PORTFOLIO_TOTAL: _FUNCTIONAL_ETH_HOLDINGS,
91+
commons_constants.PORTFOLIO_AVAILABLE: _FUNCTIONAL_ETH_HOLDINGS,
92+
},
7493
}
7594

7695

7796
async def _stub_get_all_currencies_price_ticker_no_network(self, symbols=None, **kwargs):
78-
return {}
97+
if not symbols:
98+
return {}
99+
close_column = trading_enums.ExchangeConstantsTickersColumns.CLOSE.value
100+
tickers: dict[str, dict] = {}
101+
for symbol in symbols:
102+
if symbol == f"BTC/{_EXPECTED_PORTFOLIO_UNIT}":
103+
tickers[symbol] = {close_column: _FUNCTIONAL_BTC_USDT_CLOSE}
104+
return tickers
79105

80106

81107
async def _run_user_action_to_completion(
@@ -113,6 +139,31 @@ def _assert_listed_user_actions_match_expected_id_status_pairs(
113139
assert actual_sorted == expected_sorted
114140

115141

142+
def _assert_functional_portfolio_content(
143+
portfolio_content: protocol_models.PortfolioContent | None,
144+
) -> None:
145+
assert portfolio_content is not None
146+
assert portfolio_content.unit == _EXPECTED_PORTFOLIO_UNIT
147+
assert portfolio_content.total == pytest.approx(_EXPECTED_PORTFOLIO_TOTAL)
148+
assets_by_symbol = {asset.symbol: asset for asset in portfolio_content.assets}
149+
assert set(assets_by_symbol) == {"USDT", "BTC", "ETH"}
150+
151+
usdt_asset = assets_by_symbol["USDT"]
152+
assert usdt_asset.total == pytest.approx(_FUNCTIONAL_USDT_HOLDINGS)
153+
assert usdt_asset.available == pytest.approx(_FUNCTIONAL_USDT_HOLDINGS)
154+
assert usdt_asset.value == pytest.approx(_EXPECTED_USDT_VALUE)
155+
156+
bitcoin_asset = assets_by_symbol["BTC"]
157+
assert bitcoin_asset.total == pytest.approx(_FUNCTIONAL_BTC_HOLDINGS)
158+
assert bitcoin_asset.available == pytest.approx(_FUNCTIONAL_BTC_HOLDINGS)
159+
assert bitcoin_asset.value == pytest.approx(_EXPECTED_BTC_VALUE)
160+
161+
ethereum_asset = assets_by_symbol["ETH"]
162+
assert ethereum_asset.total == pytest.approx(_FUNCTIONAL_ETH_HOLDINGS)
163+
assert ethereum_asset.available == pytest.approx(_FUNCTIONAL_ETH_HOLDINGS)
164+
assert ethereum_asset.value == pytest.approx(_EXPECTED_ETH_VALUE)
165+
166+
116167
@pytest.mark.asyncio
117168
class TestExecuteUserActionAccountCrud:
118169
async def test_create_edit_refresh_delete_accounts_on_temp_filesystem(
@@ -343,6 +394,7 @@ def build_delete_user_action(*, user_action_id: str, account_id: str) -> protoco
343394
assert persisted_created_account.state.status == protocol_models.AccountStatus.VALID
344395
assert persisted_created_account.state.message == protocol_models.AccountStatusMessage.VALID
345396
assert len(account_provider.list_items(wallet_address)) == 1
397+
_assert_functional_portfolio_content(persisted_created_account.portfolio_content)
346398

347399
# Step 3 — Edit: enqueue workflow only first; poll listings mid retry before awaiting terminal output.
348400
edited_account = build_account(
@@ -442,6 +494,7 @@ def build_delete_user_action(*, user_action_id: str, account_id: str) -> protoco
442494
assert persisted_refreshed_account.state is not None
443495
assert persisted_refreshed_account.state.status == protocol_models.AccountStatus.VALID
444496
assert persisted_refreshed_account.state.message == protocol_models.AccountStatusMessage.VALID
497+
_assert_functional_portfolio_content(persisted_refreshed_account.portfolio_content)
445498

446499
# Step 5 — Delete: remove account from provider; listing gains COMPLETED delete row.
447500
delete_action = build_delete_user_action(

packages/protocol/docs/Account.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Name | Type | Description | Notes
1313
**state** | [**AccountState**](AccountState.md) | | [optional]
1414
**created_at** | **datetime** | |
1515
**updated_at** | **datetime** | |
16-
**portfolio_content** | [**PortfolioContent**](PortfolioContent.md) | Most up-to-date content in the account portfolio. Includes total and available values | [optional]
16+
**portfolio_content** | [**PortfolioContent**](PortfolioContent.md) | | [optional]
1717
**details** | [**AccountDetails**](AccountDetails.md) | | [optional]
1818

1919
## Example

packages/protocol/octobot_protocol/models/account.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import json
1919

2020
from datetime import datetime
21-
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr
21+
from pydantic import BaseModel, ConfigDict, StrictBool, StrictStr
2222
from typing import Any, ClassVar, Dict, List, Optional
2323
from octobot_protocol.models.account_details import AccountDetails
2424
from octobot_protocol.models.account_state import AccountState
@@ -38,7 +38,7 @@ class Account(BaseModel):
3838
state: Optional[AccountState] = None
3939
created_at: datetime
4040
updated_at: datetime
41-
portfolio_content: Optional[PortfolioContent] = Field(default=None, description="Most up-to-date content in the account portfolio. Includes total and available values")
41+
portfolio_content: Optional[PortfolioContent] = None
4242
details: Optional[AccountDetails] = None
4343
__properties: ClassVar[List[str]] = ["id", "name", "is_simulated", "description", "state", "created_at", "updated_at", "portfolio_content", "details"]
4444

packages/protocol/openapi.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -849,8 +849,8 @@
849849
"format": "date-time"
850850
},
851851
"portfolio_content": {
852-
"description": "Most up-to-date content in the account portfolio. Includes total and available values",
853-
"$ref": "#/components/schemas/PortfolioContent"
852+
"$ref": "#/components/schemas/PortfolioContent",
853+
"x-field-description": "Most up-to-date content in the account portfolio. Includes total and available values"
854854
},
855855
"details": {
856856
"oneOf": [

packages/protocol/standard.rc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ contextmanager-decorators=contextlib.contextmanager
566566
# List of members which are set dynamically and missed by pylint inference
567567
# system, and so shouldn't trigger E1101 when accessed. Python regular
568568
# expressions are accepted.
569-
generated-members=.*Account\.portfolio_content
569+
generated-members=
570570

571571
# Tells whether to warn about missing members when the owner of the attribute
572572
# is inferred to be None.

0 commit comments

Comments
 (0)