From 98780dfb49b3208a92d2922198e7412fddf5439d Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Sun, 30 Jul 2023 00:01:23 +0300 Subject: [PATCH] Added model validation to remove UNSET before field validation (#1233) * Add model validation to remove UNSET before field validation Updated aiogram/types/base.py to include a model validator which removes any 'UNSET' before field validation. This change was necessary to correctly handle `parse_mode` where 'UNSET' is used as a sentinel value. Without the removal of 'UNSET', it would create issues when passed to model initialization from `Bot.method_name`. 'UNSET' was also added to typing. Tiny documentation fix was made. * Added changelog --- CHANGES/1233.bugfix.rst | 4 ++++ aiogram/types/base.py | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 CHANGES/1233.bugfix.rst diff --git a/CHANGES/1233.bugfix.rst b/CHANGES/1233.bugfix.rst new file mode 100644 index 00000000..17aa8fbc --- /dev/null +++ b/CHANGES/1233.bugfix.rst @@ -0,0 +1,4 @@ +Added model validation to remove UNSET before field validation. +This change was necessary to correctly handle parse_mode where 'UNSET' is used as a sentinel value. +Without the removal of 'UNSET', it would create issues when passed to model initialization from Bot.method_name. +'UNSET' was also added to typing. diff --git a/aiogram/types/base.py b/aiogram/types/base.py index 641b16df..9c24c703 100644 --- a/aiogram/types/base.py +++ b/aiogram/types/base.py @@ -1,7 +1,7 @@ -from typing import Any +from typing import Any, Dict from unittest.mock import sentinel -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, model_validator from aiogram.client.context_controller import BotContextController @@ -17,6 +17,19 @@ class TelegramObject(BotContextController, BaseModel): defer_build=True, ) + @model_validator(mode="before") + @classmethod + def remove_unset(cls, values: Dict[str, Any]) -> Dict[str, Any]: + """ + Remove UNSET before fields validation. + + We use UNSET as a sentinel value for `parse_mode` and replace it to real value later. + It isn't a problem when it's just default value for a model field, + but UNSET might be passed to a model initialization from `Bot.method_name`, + so we must take care of it and remove it before fields validation. + """ + return {k: v for k, v in values.items() if not isinstance(v, UNSET_TYPE)} + class MutableTelegramObject(TelegramObject): model_config = ConfigDict( @@ -24,7 +37,7 @@ class MutableTelegramObject(TelegramObject): ) -# special sentinel object which used in situation when None might be a useful value +# special sentinel object which used in a situation when None might be a useful value UNSET: Any = sentinel.UNSET UNSET_PARSE_MODE: Any = sentinel.UNSET_PARSE_MODE UNSET_DISABLE_WEB_PAGE_PREVIEW: Any = sentinel.UNSET_DISABLE_WEB_PAGE_PREVIEW