From 02ec945a965584d26512eb5b424028c31da897e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:45:59 +0000 Subject: [PATCH 01/17] Bump pydantic from 1.10.11 to 2.1.1 Bumps [pydantic](https://github.com/pydantic/pydantic) from 1.10.11 to 2.1.1. - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md) - [Commits](https://github.com/pydantic/pydantic/compare/v1.10.11...v2.1.1) --- updated-dependencies: - dependency-name: pydantic dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dd079329f..5ac592a3b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -40,7 +40,7 @@ sdnotify==0.3.2 # API Server fastapi==0.100.1 -pydantic==1.10.11 +pydantic==2.1.1 uvicorn==0.23.2 pyjwt==2.8.0 aiofiles==23.1.0 From 261a593ba56ae9ecb8d82ab438f6d824f7c9f163 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 31 Jul 2023 18:04:25 +0200 Subject: [PATCH 02/17] Update tests for new output format (string-formatted dates are not relevant). --- freqtrade/rpc/api_server/api_schemas.py | 6 +++--- tests/rpc/test_rpc_apiserver.py | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index bd405d22b..4c674e05e 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -1,7 +1,7 @@ from datetime import date, datetime from typing import Any, Dict, List, Optional, Union -from pydantic import BaseModel +from pydantic import BaseModel, SerializeAsAny from freqtrade.constants import DATETIME_PRINT_FORMAT, IntOrInf from freqtrade.enums import MarginMode, OrderTypeValues, SignalDirection, TradingMode @@ -470,7 +470,7 @@ class PairHistory(BaseModel): timeframe: str timeframe_ms: int columns: List[str] - data: List[Any] + data: SerializeAsAny[List[Any]] length: int buy_signals: int sell_signals: int @@ -517,7 +517,7 @@ class BacktestResponse(BaseModel): progress: float trade_count: Optional[float] # TODO: Properly type backtestresult... - backtest_result: Optional[Dict[str, Any]] + backtest_result: SerializeAsAny[Optional[Dict[str, Any]]] = None # TODO: This is a copy of BacktestHistoryEntryType diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index abbaa421e..131606aab 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1418,12 +1418,12 @@ def test_api_pair_candles(botclient, ohlcv_history): assert len(rc.json()['data']) == amount assert (rc.json()['data'] == - [['2017-11-26 08:50:00', 8.794e-05, 8.948e-05, 8.794e-05, 8.88e-05, 0.0877869, + [['2017-11-26T08:50:00Z', 8.794e-05, 8.948e-05, 8.794e-05, 8.88e-05, 0.0877869, None, 0, 0, 0, 0, 1511686200000, None, None, None, None], - ['2017-11-26 08:55:00', 8.88e-05, 8.942e-05, 8.88e-05, + ['2017-11-26T08:55:00Z', 8.88e-05, 8.942e-05, 8.88e-05, 8.893e-05, 0.05874751, 8.886500000000001e-05, 1, 0, 0, 0, 1511686500000, 8.893e-05, None, None, None], - ['2017-11-26 09:00:00', 8.891e-05, 8.893e-05, 8.875e-05, 8.877e-05, + ['2017-11-26T09:00:00Z', 8.891e-05, 8.893e-05, 8.875e-05, 8.877e-05, 0.7039405, 8.885e-05, 0, 0, 0, 0, 1511686800000, None, None, None, None] ]) @@ -1437,13 +1437,13 @@ def test_api_pair_candles(botclient, ohlcv_history): f"{BASE_URI}/pair_candles?limit={amount}&pair=XRP%2FBTC&timeframe={timeframe}") assert_response(rc) assert (rc.json()['data'] == - [['2017-11-26 08:50:00', 8.794e-05, 8.948e-05, 8.794e-05, 8.88e-05, 0.0877869, + [['2017-11-26T08:50:00Z', 8.794e-05, 8.948e-05, 8.794e-05, 8.88e-05, 0.0877869, None, 0, None, 0, 0, None, 1511686200000, None, None, None, None], - ['2017-11-26 08:55:00', 8.88e-05, 8.942e-05, 8.88e-05, - 8.893e-05, 0.05874751, 8.886500000000001e-05, 1, 0.0, 0, 0, '2017-11-26 08:55:00', + ['2017-11-26T08:55:00Z', 8.88e-05, 8.942e-05, 8.88e-05, + 8.893e-05, 0.05874751, 8.886500000000001e-05, 1, 0.0, 0, 0, '2017-11-26T08:55:00Z', 1511686500000, 8.893e-05, None, None, None], - ['2017-11-26 09:00:00', 8.891e-05, 8.893e-05, 8.875e-05, 8.877e-05, - 0.7039405, 8.885e-05, 0, 0.0, 0, 0, '2017-11-26 09:00:00', 1511686800000, + ['2017-11-26T09:00:00Z', 8.891e-05, 8.893e-05, 8.875e-05, 8.877e-05, + 0.7039405, 8.885e-05, 0, 0.0, 0, 0, '2017-11-26T09:00:00Z', 1511686800000, None, None, None, None] ]) @@ -1500,7 +1500,7 @@ def test_api_pair_history(botclient, mocker): date_col_idx = [idx for idx, c in enumerate(result['columns']) if c == 'date'][0] rsi_col_idx = [idx for idx, c in enumerate(result['columns']) if c == 'rsi'][0] - assert data[0][date_col_idx] == '2018-01-11 00:00:00' + assert data[0][date_col_idx] == '2018-01-11T00:00:00Z' assert data[0][rsi_col_idx] is not None assert data[0][rsi_col_idx] > 0 assert lfm.call_count == 1 From 9b924f1f85fb76945f7b6b969e0d98fad61440c3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 06:43:36 +0200 Subject: [PATCH 03/17] Convert ws_schemas to pydantic 2.0 --- freqtrade/rpc/api_server/ws_schemas.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/freqtrade/rpc/api_server/ws_schemas.py b/freqtrade/rpc/api_server/ws_schemas.py index af98bd532..9167487b4 100644 --- a/freqtrade/rpc/api_server/ws_schemas.py +++ b/freqtrade/rpc/api_server/ws_schemas.py @@ -2,15 +2,14 @@ from datetime import datetime from typing import Any, Dict, List, Optional, TypedDict from pandas import DataFrame -from pydantic import BaseModel +from pydantic import ConfigDict, BaseModel from freqtrade.constants import PairWithTimeframe from freqtrade.enums.rpcmessagetype import RPCMessageType, RPCRequestType class BaseArbitraryModel(BaseModel): - class Config: - arbitrary_types_allowed = True + model_config = ConfigDict(arbitrary_types_allowed=True) class WSRequestSchema(BaseArbitraryModel): @@ -27,9 +26,7 @@ class WSMessageSchemaType(TypedDict): class WSMessageSchema(BaseArbitraryModel): type: RPCMessageType data: Optional[Any] = None - - class Config: - extra = 'allow' + model_config = ConfigDict(extra='allow') # ------------------------------ REQUEST SCHEMAS ---------------------------- From 53c76160a70c2d2b68e370a52515a1eb2b83d133 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 06:44:10 +0200 Subject: [PATCH 04/17] Force pydantic > 2.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c2b725f87..4a01713e3 100644 --- a/setup.py +++ b/setup.py @@ -97,7 +97,7 @@ setup( 'rich', 'pyarrow; platform_machine != "armv7l"', 'fastapi', - 'pydantic>=1.8.0,<2.0', + 'pydantic>=2.0.0', 'uvicorn', 'psutil', 'pyjwt', From cfdd01d295548008429257f7b4bce5f3d908cdc6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 06:44:33 +0200 Subject: [PATCH 05/17] Update most of Api schema to pydantic 2.0 --- freqtrade/rpc/api_server/api_schemas.py | 214 ++++++++++++------------ 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 4c674e05e..6d7c12c27 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -9,9 +9,9 @@ from freqtrade.types import ValidExchangesType class ExchangeModePayloadMixin(BaseModel): - trading_mode: Optional[TradingMode] - margin_mode: Optional[MarginMode] - exchange: Optional[str] + trading_mode: Optional[TradingMode] = None + margin_mode: Optional[MarginMode] = None + exchange: Optional[str] = None class Ping(BaseModel): @@ -43,11 +43,11 @@ class BackgroundTaskStatus(BaseModel): job_category: str status: str running: bool - progress: Optional[float] + progress: Optional[float] = None class BackgroundTaskResult(BaseModel): - error: Optional[str] + error: Optional[str] = None status: str @@ -60,9 +60,9 @@ class Balance(BaseModel): free: float balance: float used: float - bot_owned: Optional[float] + bot_owned: Optional[float] = None est_stake: float - est_stake_bot: Optional[float] + est_stake_bot: Optional[float] = None stake: str # Starting with 2.x side: str @@ -141,7 +141,7 @@ class Profit(BaseModel): expectancy_ratio: float max_drawdown: float max_drawdown_abs: float - trading_volume: Optional[float] + trading_volume: Optional[float] = None bot_start_timestamp: int bot_start_date: str @@ -173,50 +173,50 @@ class Daily(BaseModel): class UnfilledTimeout(BaseModel): - entry: Optional[int] - exit: Optional[int] - unit: Optional[str] - exit_timeout_count: Optional[int] + entry: Optional[int] = None + exit: Optional[int] = None + unit: Optional[str] = None + exit_timeout_count: Optional[int] = None class OrderTypes(BaseModel): entry: OrderTypeValues exit: OrderTypeValues - emergency_exit: Optional[OrderTypeValues] - force_exit: Optional[OrderTypeValues] - force_entry: Optional[OrderTypeValues] + emergency_exit: Optional[OrderTypeValues] = None + force_exit: Optional[OrderTypeValues] = None + force_entry: Optional[OrderTypeValues] = None stoploss: OrderTypeValues stoploss_on_exchange: bool - stoploss_on_exchange_interval: Optional[int] + stoploss_on_exchange_interval: Optional[int] = None class ShowConfig(BaseModel): version: str - strategy_version: Optional[str] + strategy_version: Optional[str] = None api_version: float dry_run: bool trading_mode: str short_allowed: bool stake_currency: str stake_amount: str - available_capital: Optional[float] + available_capital: Optional[float] = None stake_currency_decimals: int max_open_trades: IntOrInf minimal_roi: Dict[str, Any] - stoploss: Optional[float] + stoploss: Optional[float] = None stoploss_on_exchange: bool - trailing_stop: Optional[bool] - trailing_stop_positive: Optional[float] - trailing_stop_positive_offset: Optional[float] - trailing_only_offset_is_reached: Optional[bool] - unfilledtimeout: Optional[UnfilledTimeout] # Empty in webserver mode - order_types: Optional[OrderTypes] - use_custom_stoploss: Optional[bool] - timeframe: Optional[str] + trailing_stop: Optional[bool] = None + trailing_stop_positive: Optional[float] = None + trailing_stop_positive_offset: Optional[float] = None + trailing_only_offset_is_reached: Optional[bool] = None + unfilledtimeout: Optional[UnfilledTimeout] = None # Empty in webserver mode + order_types: Optional[OrderTypes] = None + use_custom_stoploss: Optional[bool] = None + timeframe: Optional[str] = None timeframe_ms: int timeframe_min: int exchange: str - strategy: Optional[str] + strategy: Optional[str] = None force_entry_enable: bool exit_pricing: Dict[str, Any] entry_pricing: Dict[str, Any] @@ -231,17 +231,17 @@ class OrderSchema(BaseModel): pair: str order_id: str status: str - remaining: Optional[float] + remaining: Optional[float] = None amount: float safe_price: float cost: float - filled: Optional[float] + filled: Optional[float] = None ft_order_side: str order_type: str is_open: bool - order_timestamp: Optional[int] - order_filled_timestamp: Optional[int] - ft_fee_base: Optional[float] + order_timestamp: Optional[int] = None + order_filled_timestamp: Optional[int] = None + ft_fee_base: Optional[float] = None class TradeSchema(BaseModel): @@ -255,81 +255,81 @@ class TradeSchema(BaseModel): amount: float amount_requested: float stake_amount: float - max_stake_amount: Optional[float] + max_stake_amount: Optional[float] = None strategy: str - enter_tag: Optional[str] + enter_tag: Optional[str] = None timeframe: int - fee_open: Optional[float] - fee_open_cost: Optional[float] - fee_open_currency: Optional[str] - fee_close: Optional[float] - fee_close_cost: Optional[float] - fee_close_currency: Optional[str] + fee_open: Optional[float] = None + fee_open_cost: Optional[float] = None + fee_open_currency: Optional[str] = None + fee_close: Optional[float] = None + fee_close_cost: Optional[float] = None + fee_close_currency: Optional[str] = None open_date: str open_timestamp: int open_rate: float - open_rate_requested: Optional[float] + open_rate_requested: Optional[float] = None open_trade_value: float - close_date: Optional[str] - close_timestamp: Optional[int] - close_rate: Optional[float] - close_rate_requested: Optional[float] + close_date: Optional[str] = None + close_timestamp: Optional[int] = None + close_rate: Optional[float] = None + close_rate_requested: Optional[float] = None - close_profit: Optional[float] - close_profit_pct: Optional[float] - close_profit_abs: Optional[float] + close_profit: Optional[float] = None + close_profit_pct: Optional[float] = None + close_profit_abs: Optional[float] = None - profit_ratio: Optional[float] - profit_pct: Optional[float] - profit_abs: Optional[float] - profit_fiat: Optional[float] + profit_ratio: Optional[float] = None + profit_pct: Optional[float] = None + profit_abs: Optional[float] = None + profit_fiat: Optional[float] = None realized_profit: float - realized_profit_ratio: Optional[float] + realized_profit_ratio: Optional[float] = None - exit_reason: Optional[str] - exit_order_status: Optional[str] + exit_reason: Optional[str] = None + exit_order_status: Optional[str] = None - stop_loss_abs: Optional[float] - stop_loss_ratio: Optional[float] - stop_loss_pct: Optional[float] - stoploss_order_id: Optional[str] - stoploss_last_update: Optional[str] - stoploss_last_update_timestamp: Optional[int] - initial_stop_loss_abs: Optional[float] - initial_stop_loss_ratio: Optional[float] - initial_stop_loss_pct: Optional[float] + stop_loss_abs: Optional[float] = None + stop_loss_ratio: Optional[float] = None + stop_loss_pct: Optional[float] = None + stoploss_order_id: Optional[str] = None + stoploss_last_update: Optional[str] = None + stoploss_last_update_timestamp: Optional[int] = None + initial_stop_loss_abs: Optional[float] = None + initial_stop_loss_ratio: Optional[float] = None + initial_stop_loss_pct: Optional[float] = None - min_rate: Optional[float] - max_rate: Optional[float] - open_order_id: Optional[str] + min_rate: Optional[float] = None + max_rate: Optional[float] = None + open_order_id: Optional[str] = None orders: List[OrderSchema] - leverage: Optional[float] - interest_rate: Optional[float] - liquidation_price: Optional[float] - funding_fees: Optional[float] - trading_mode: Optional[TradingMode] + leverage: Optional[float] = None + interest_rate: Optional[float] = None + liquidation_price: Optional[float] = None + funding_fees: Optional[float] = None + trading_mode: Optional[TradingMode] = None - amount_precision: Optional[float] - price_precision: Optional[float] - precision_mode: Optional[int] + amount_precision: Optional[float] = None + price_precision: Optional[float] = None + precision_mode: Optional[int] = None class OpenTradeSchema(TradeSchema): - stoploss_current_dist: Optional[float] - stoploss_current_dist_pct: Optional[float] - stoploss_current_dist_ratio: Optional[float] - stoploss_entry_dist: Optional[float] - stoploss_entry_dist_ratio: Optional[float] + stoploss_current_dist: Optional[float] = None + stoploss_current_dist_pct: Optional[float] = None + stoploss_current_dist_ratio: Optional[float] = None + stoploss_entry_dist: Optional[float] = None + stoploss_entry_dist_ratio: Optional[float] = None current_rate: float total_profit_abs: float - total_profit_fiat: Optional[float] - total_profit_ratio: Optional[float] + total_profit_fiat: Optional[float] = None + total_profit_ratio: Optional[float] = None - open_order: Optional[str] + open_order: Optional[str] = None class TradeResponse(BaseModel): @@ -352,7 +352,7 @@ class LockModel(BaseModel): lock_timestamp: int pair: str side: str - reason: Optional[str] + reason: Optional[str] = None class Locks(BaseModel): @@ -361,8 +361,8 @@ class Locks(BaseModel): class DeleteLockRequest(BaseModel): - pair: Optional[str] - lockid: Optional[int] + pair: Optional[str] = None + lockid: Optional[int] = None class Logs(BaseModel): @@ -373,17 +373,17 @@ class Logs(BaseModel): class ForceEnterPayload(BaseModel): pair: str side: SignalDirection = SignalDirection.LONG - price: Optional[float] - ordertype: Optional[OrderTypeValues] - stakeamount: Optional[float] - entry_tag: Optional[str] - leverage: Optional[float] + price: Optional[float] = None + ordertype: Optional[OrderTypeValues] = None + stakeamount: Optional[float] = None + entry_tag: Optional[str] = None + leverage: Optional[float] = None class ForceExitPayload(BaseModel): tradeid: str - ordertype: Optional[OrderTypeValues] - amount: Optional[float] + ordertype: Optional[OrderTypeValues] = None + amount: Optional[float] = None class BlacklistPayload(BaseModel): @@ -405,7 +405,7 @@ class WhitelistResponse(BaseModel): class WhitelistEvaluateResponse(BackgroundTaskResult): - result: Optional[WhitelistResponse] + result: Optional[WhitelistResponse] = None class DeleteTrade(BaseModel): @@ -497,16 +497,16 @@ class BacktestFreqAIInputs(BaseModel): class BacktestRequest(BaseModel): strategy: str - timeframe: Optional[str] - timeframe_detail: Optional[str] - timerange: Optional[str] - max_open_trades: Optional[IntOrInf] - stake_amount: Optional[str] + timeframe: Optional[str] = None + timeframe_detail: Optional[str] = None + timerange: Optional[str] = None + max_open_trades: Optional[IntOrInf] = None + stake_amount: Optional[str] = None enable_protections: bool - dry_run_wallet: Optional[float] - backtest_cache: Optional[str] - freqaimodel: Optional[str] - freqai: Optional[BacktestFreqAIInputs] + dry_run_wallet: Optional[float] = None + backtest_cache: Optional[str] = None + freqaimodel: Optional[str] = None + freqai: Optional[BacktestFreqAIInputs] = None class BacktestResponse(BaseModel): @@ -515,7 +515,7 @@ class BacktestResponse(BaseModel): status_msg: str step: str progress: float - trade_count: Optional[float] + trade_count: Optional[float] = None # TODO: Properly type backtestresult... backtest_result: SerializeAsAny[Optional[Dict[str, Any]]] = None @@ -534,5 +534,5 @@ class SysInfo(BaseModel): class Health(BaseModel): - last_process: Optional[datetime] - last_process_ts: Optional[int] + last_process: Optional[datetime] = None + last_process_ts: Optional[int] = None From e36c5452581841e1ef41e102dc5e8eb88a6eec26 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 06:52:09 +0200 Subject: [PATCH 06/17] pydantic - root model --- freqtrade/rpc/api_server/api_schemas.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 6d7c12c27..02f24fba1 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -339,8 +339,7 @@ class TradeResponse(BaseModel): total_trades: int -class ForceEnterResponse(BaseModel): - __root__: Union[TradeSchema, StatusMsg] +ForceEnterResponse = RootModel[Union[TradeSchema, StatusMsg]] class LockModel(BaseModel): @@ -420,8 +419,7 @@ class PlotConfig_(BaseModel): subplots: Dict[str, Any] -class PlotConfig(BaseModel): - __root__: Union[PlotConfig_, Dict] +PlotConfig = RootModel[Union[PlotConfig_, Dict]] class StrategyListResponse(BaseModel): From 505584dc4855185b7f4d91cb75309829aa62e5c7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 07:05:30 +0200 Subject: [PATCH 07/17] pydantic 2 - update deprecated methods --- freqtrade/rpc/api_server/api_v1.py | 6 +++--- freqtrade/rpc/external_message_consumer.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index 3e5d55f71..08c26c59b 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -174,9 +174,9 @@ def force_entry(payload: ForceEnterPayload, rpc: RPC = Depends(get_rpc)): leverage=payload.leverage) if trade: - return ForceEnterResponse.parse_obj(trade.to_json()) + return ForceEnterResponse.model_validate(trade.to_json()) else: - return ForceEnterResponse.parse_obj( + return ForceEnterResponse.model_validate( {"status": f"Error entering {payload.side} trade for pair {payload.pair}."}) @@ -281,7 +281,7 @@ def plot_config(strategy: Optional[str] = None, config=Depends(get_config), if not strategy: if not rpc: raise RPCException("Strategy is mandatory in webserver mode.") - return PlotConfig.parse_obj(rpc._rpc_plot_config()) + return PlotConfig.model_validate(rpc._rpc_plot_config()) else: config1 = deepcopy(config) config1.update({ diff --git a/freqtrade/rpc/external_message_consumer.py b/freqtrade/rpc/external_message_consumer.py index e888191ea..c725f553b 100644 --- a/freqtrade/rpc/external_message_consumer.py +++ b/freqtrade/rpc/external_message_consumer.py @@ -322,7 +322,7 @@ class ExternalMessageConsumer: producer_name = producer.get('name', 'default') try: - producer_message = WSMessageSchema.parse_obj(message) + producer_message = WSMessageSchema.model_validate(message) except ValidationError as e: logger.error(f"Invalid message from `{producer_name}`: {e}") return @@ -344,7 +344,7 @@ class ExternalMessageConsumer: def _consume_whitelist_message(self, producer_name: str, message: WSMessageSchema): try: # Validate the message - whitelist_message = WSWhitelistMessage.parse_obj(message) + whitelist_message = WSWhitelistMessage.model_validate(message) except ValidationError as e: logger.error(f"Invalid message from `{producer_name}`: {e}") return @@ -356,7 +356,7 @@ class ExternalMessageConsumer: def _consume_analyzed_df_message(self, producer_name: str, message: WSMessageSchema): try: - df_message = WSAnalyzedDFMessage.parse_obj(message) + df_message = WSAnalyzedDFMessage.model_validate(message) except ValidationError as e: logger.error(f"Invalid message from `{producer_name}`: {e}") return From 4b2a6a84f4d280ceab887c7785042aa4c9e956d7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 07:08:18 +0200 Subject: [PATCH 08/17] Remove more deprecated options --- freqtrade/rpc/external_message_consumer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/external_message_consumer.py b/freqtrade/rpc/external_message_consumer.py index c725f553b..200d408e6 100644 --- a/freqtrade/rpc/external_message_consumer.py +++ b/freqtrade/rpc/external_message_consumer.py @@ -41,7 +41,7 @@ logger = logging.getLogger(__name__) def schema_to_dict(schema: Union[WSMessageSchema, WSRequestSchema]): - return schema.dict(exclude_none=True) + return schema.model_dump(exclude_none=True) class ExternalMessageConsumer: @@ -344,7 +344,7 @@ class ExternalMessageConsumer: def _consume_whitelist_message(self, producer_name: str, message: WSMessageSchema): try: # Validate the message - whitelist_message = WSWhitelistMessage.model_validate(message) + whitelist_message = WSWhitelistMessage.model_validate(message.model_dump()) except ValidationError as e: logger.error(f"Invalid message from `{producer_name}`: {e}") return @@ -356,7 +356,7 @@ class ExternalMessageConsumer: def _consume_analyzed_df_message(self, producer_name: str, message: WSMessageSchema): try: - df_message = WSAnalyzedDFMessage.model_validate(message) + df_message = WSAnalyzedDFMessage.model_validate(message.model_dump()) except ValidationError as e: logger.error(f"Invalid message from `{producer_name}`: {e}") return From bb18e1b45b860445baa45b18cccc3506fb68eb5f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 18:19:42 +0200 Subject: [PATCH 09/17] Fix part of the backtest type error --- freqtrade/rpc/api_server/api_schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 02f24fba1..15d5feb86 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -499,7 +499,7 @@ class BacktestRequest(BaseModel): timeframe_detail: Optional[str] = None timerange: Optional[str] = None max_open_trades: Optional[IntOrInf] = None - stake_amount: Optional[str] = None + stake_amount: Optional[Union[str, float]] = None enable_protections: bool dry_run_wallet: Optional[float] = None backtest_cache: Optional[str] = None From 47850ce1b0af78e73b70f739333efc30b107abf0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 18:22:36 +0200 Subject: [PATCH 10/17] Don''t use deprecated pydantic methods --- freqtrade/rpc/api_server/api_ws.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/api_server/api_ws.py b/freqtrade/rpc/api_server/api_ws.py index 40a5a75fd..16aeb56f3 100644 --- a/freqtrade/rpc/api_server/api_ws.py +++ b/freqtrade/rpc/api_server/api_ws.py @@ -65,7 +65,7 @@ async def _process_consumer_request( """ # Validate the request, makes sure it matches the schema try: - websocket_request = WSRequestSchema.parse_obj(request) + websocket_request = WSRequestSchema.model_validate(request) except ValidationError as e: logger.error(f"Invalid request from {channel}: {e}") return @@ -94,7 +94,7 @@ async def _process_consumer_request( # Format response response = WSWhitelistMessage(data=whitelist) - await channel.send(response.dict(exclude_none=True)) + await channel.send(response.model_dump(exclude_none=True)) elif type_ == RPCRequestType.ANALYZED_DF: # Limit the amount of candles per dataframe to 'limit' or 1500 @@ -105,7 +105,7 @@ async def _process_consumer_request( for message in rpc._ws_request_analyzed_df(limit, pair): # Format response response = WSAnalyzedDFMessage(data=message) - await channel.send(response.dict(exclude_none=True)) + await channel.send(response.model_dump(exclude_none=True)) @router.websocket("/message/ws") From d78eb834c419e2a44a494d1a9fc8d20bcc141083 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Jul 2023 18:23:58 +0200 Subject: [PATCH 11/17] Convert to pydantic - jsonencoders (no longer exists) --- freqtrade/rpc/api_server/api_schemas.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 15d5feb86..61a1a65d8 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -482,11 +482,11 @@ class PairHistory(BaseModel): data_start: str data_stop: str data_stop_ts: int - - class Config: - json_encoders = { - datetime: lambda v: v.strftime(DATETIME_PRINT_FORMAT), - } + # TODO[pydantic]: The following keys were removed: `json_encoders`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(json_encoders={ + datetime: lambda v: v.strftime(DATETIME_PRINT_FORMAT), + }) class BacktestFreqAIInputs(BaseModel): @@ -515,7 +515,7 @@ class BacktestResponse(BaseModel): progress: float trade_count: Optional[float] = None # TODO: Properly type backtestresult... - backtest_result: SerializeAsAny[Optional[Dict[str, Any]]] = None + backtest_result: SerializeAsAny[Optional[Dict[str, Any]]] # TODO: This is a copy of BacktestHistoryEntryType From 3b416223e398d7fa25da2be62120a7cfbbff46c4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 31 Jul 2023 16:55:39 +0200 Subject: [PATCH 12/17] Bump pydantic to 2.1.1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4a01713e3..356bb9fe6 100644 --- a/setup.py +++ b/setup.py @@ -97,7 +97,7 @@ setup( 'rich', 'pyarrow; platform_machine != "armv7l"', 'fastapi', - 'pydantic>=2.0.0', + 'pydantic>=2.1.1', 'uvicorn', 'psutil', 'pyjwt', From 494d58e79c11cd65c31ba73dc76a46c928133e35 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 31 Jul 2023 18:04:25 +0200 Subject: [PATCH 13/17] Update tests for new output format (string-formatted dates are not relevant). --- freqtrade/rpc/api_server/api_schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 61a1a65d8..7e4f60187 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -1,7 +1,7 @@ from datetime import date, datetime from typing import Any, Dict, List, Optional, Union -from pydantic import BaseModel, SerializeAsAny +from pydantic import BaseModel, ConfigDict, RootModel, SerializeAsAny from freqtrade.constants import DATETIME_PRINT_FORMAT, IntOrInf from freqtrade.enums import MarginMode, OrderTypeValues, SignalDirection, TradingMode From 33d3c4f7d5caa294ddf9741b475c3144bfbe5346 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 7 Aug 2023 20:11:30 +0200 Subject: [PATCH 14/17] Improve backtestResponse in preparation for future update --- freqtrade/rpc/api_server/api_schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 7e4f60187..b16a2c661 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -515,7 +515,7 @@ class BacktestResponse(BaseModel): progress: float trade_count: Optional[float] = None # TODO: Properly type backtestresult... - backtest_result: SerializeAsAny[Optional[Dict[str, Any]]] + backtest_result: Optional[Dict[str, Any]] = None # TODO: This is a copy of BacktestHistoryEntryType From 352f0fdfcaca47a7f164fb9af0ca2bc6fe28f33e Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 18 Aug 2023 10:19:13 +0200 Subject: [PATCH 15/17] Bump pydantic to 2.2.0 --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 922daf80b..8a5a51c6c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -40,7 +40,7 @@ sdnotify==0.3.2 # API Server fastapi==0.101.0 -pydantic==2.1.1 +pydantic==2.2.0 uvicorn==0.23.2 pyjwt==2.8.0 aiofiles==23.2.1 diff --git a/setup.py b/setup.py index 356bb9fe6..2e92d0839 100644 --- a/setup.py +++ b/setup.py @@ -97,7 +97,7 @@ setup( 'rich', 'pyarrow; platform_machine != "armv7l"', 'fastapi', - 'pydantic>=2.1.1', + 'pydantic>=2.2.0', 'uvicorn', 'psutil', 'pyjwt', From 185c5a779d0497a0013796823e42675c588ee0fc Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 18 Aug 2023 10:21:50 +0200 Subject: [PATCH 16/17] use model_validate instead of parse_obj --- freqtrade/rpc/api_server/api_v1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index 2e2d57edc..7299364a8 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -289,7 +289,7 @@ def plot_config(strategy: Optional[str] = None, config=Depends(get_config), 'strategy': strategy }) try: - return PlotConfig.parse_obj(RPC._rpc_plot_config_with_strategy(config1)) + return PlotConfig.model_validate(RPC._rpc_plot_config_with_strategy(config1)) except Exception as e: raise HTTPException(status_code=502, detail=str(e)) From 277cc0a523be452cf1483f4463305d0af7791d9c Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 18 Aug 2023 10:55:05 +0200 Subject: [PATCH 17/17] Fix import sort order --- freqtrade/rpc/api_server/ws_schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/ws_schemas.py b/freqtrade/rpc/api_server/ws_schemas.py index 9167487b4..34eaf0245 100644 --- a/freqtrade/rpc/api_server/ws_schemas.py +++ b/freqtrade/rpc/api_server/ws_schemas.py @@ -2,7 +2,7 @@ from datetime import datetime from typing import Any, Dict, List, Optional, TypedDict from pandas import DataFrame -from pydantic import ConfigDict, BaseModel +from pydantic import BaseModel, ConfigDict from freqtrade.constants import PairWithTimeframe from freqtrade.enums.rpcmessagetype import RPCMessageType, RPCRequestType