pythontypeerrorpydanticaiogram

Aiogram legacy code: TypeError: descriptor '__pydantic_extra__' for 'BaseModel' objects doesn't apply to a 'KeyboardButton' object


aiogram==3.1.1
pydantic==2.3.0
pydantic_core==2.6.3

I've updated aiogram to a newer version and expected magic unicorns to fill my code with amusement. However, now everything that used to be working fails to work due to clashes with pydantic (yes, I've uninstalled all packages related to aiogram, including pydantic, so that it could download a compatible version itself). I have also dealt with imports from parts of aiogram moved elsewhere, so everything should have been fine now.

I fail to run everything, but I suspect this part of the code might contain either a bug or my own mistake:

view_profile = KeyboardButton(text='My profile 🥷')
delete_account = KeyboardButton(text='Delete account 🗑')
send_help = KeyboardButton(text='Help 🤯')
show_cards = KeyboardButton(text='Cards 🃏')

main_menu = ReplyKeyboardMarkup(resize_keyboard=True).add(view_profile,
                                                          delete_account,
                                                          show_cards,
                                                          send_help)

It causes this:

File ~/bots/***/venv/lib/python3.10/site-packages/pydantic/main.py:165 in __init__
    __pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)

TypeError: descriptor '__pydantic_extra__' for 'BaseModel' objects doesn't apply to a 'KeyboardButton' object

Having double-checked the documentation, here I am, puzzled and infuriated, as I found no related updates there. Maybe I'm inattentive? Can anyone tell me how to properly assign keys to a keyboard in aiogram==3.1.1? Is it a bug or can it be dealt with? I have no desire to downgrade, though the more error messages I receive whatever I do, the more I settle with this idea.


Solution

  • No idea how did you get this error (I could not reproduce it), but for sure you are using the old structure.

    Shortly, for ReplyKeyboardMarkup you should use this structure:

    main_menu = ReplyKeyboardMarkup(keyboard=[[
                KeyboardButton(text="My profile 🥷"), KeyboardButton(text="Delete account 🗑" . . .)
                ]]) 
    
    await message.answer("Hello.", reply_markup=main_menu)
    

    And for ReplyKeyboardBuilder this one:

    view_profile = KeyboardButton(text='My profile 🥷')
    delete_account = KeyboardButton(text='Delete account 🗑')
    send_help = KeyboardButton(text='Help 🤯')
    show_cards = KeyboardButton(text='Cards 🃏')
    main_menu = ReplyKeyboardBuilder().add(view_profile, delete_account, show_cards, send_help)
    
    await message.answer("Hello.", reply_markup=main_menu.as_markup())
    

    Of course you can use loops and other tools to make it more compact and beautiful. ReplyKeyboardMarkup: https://docs.aiogram.dev/en/latest/api/types/reply_keyboard_markup.html
    ReplyKeyboardBuilder + few more things: https://docs.aiogram.dev/en/latest/utils/keyboard.html.