brief-survey


Namebrief-survey JSON
Version 0.2.8.2 PyPI version JSON
download
home_pagehttps://github.com/Fugguri/brief_survey
SummaryDynamic survey/dialog for aiogram3 with aiogram_dialog and Pydantic support
upload_time2025-08-13 10:35:58
maintainerNone
docs_urlNone
authorFugguri
requires_python>=3.12
licenseNone
keywords aiogram3 aiogram aiogram_dialog brief
VCS
bugtrack_url
requirements aiogram aiogram_dialog phonenumbers pydantic setuptools
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Оглавление

## 🇺🇸 English

- [BriefSurvey](#briefsurvey)
- [Description](#description)
- [Installation](#installation)
  - [From GitHub Repository](#from-github-repository)
  - [Download Locally and Install](#download-locally-and-install)
- [Quick Start](#quick-start)
  - [(case 1) Dynamic create a brief](#case-1-dynamic-crate-a-brief)
  - [(case 2)](#case-2)
    - [1. Define your questions using Pydantic models](#1-define-your-questions-using-pydantic-models)
    - [2. Define a result model](#2-define-a-result-model)
    - [3. Create a function to save results](#3-create-a-function-to-save-results)
    - [4. Initialize and register the survey](#4-initialize-and-register-the-survey)
    - [5. Launch the survey in Telegram with the command](#5-launch-the-survey-in-telegram-with-the-command)
- [Important](#important)
- [Customizing Messages and Buttons in brief_survey](#customizing-messages-and-buttons-in-brief_survey)
  - [What can be customized (English)](#what-can-be-customized-english)
    - [InfoMessages — system messages](#infomessages-—-system-messages)
    - [InfoButtons — button labels](#infobuttons-—-button-labels)
  - [Example usage](#example-usage)

## 🇷🇺 Русский

- [BriefSurvey](#briefsurvey)
- [Описание](#описание)
- [Установка](#установка)
  - [Github Repo](#github-repo)
  - [Скачать локально и установить](#скачать-локально-и-установить)
- [Быстрый старт](#быстрый-старт)
  - [(1 вариант) Динамическое добавление вопросов](#1-вариант-динамическое-добавление-вопросов)
  - [(2 вариант)](#2-вариант)
    - [1. Определите вопросы](#1-определите-вопросы)
    - [2. Определите модель результата](#2-определите-модель-результата)
    - [3. Создайте функцию для сохранения результатов](#3-создайте-функцию-для-сохранения-результатов)
    - [4. Инициализируйте и зарегистрируйте опросник](#4-инициализируйте-и-зарегистрируйте-опросник)
    - [5. Запускайте команду в Telegram](#5запускайте-команду-в-telegram)
- [Важно](#важно)
- [Настройка сообщений и кнопок в brief_survey](#настройка-сообщений-и-кнопок-в-brief_survey)
  - [Что можно настраивать](#что-можно-настраивать)
    - [InfoMessages — системные сообщения](#infomessages-—-системные-сообщения)
    - [InfoButtons — тексты кнопок](#infobuttons-—-тексты-кнопок)
  - [Пример использования](#пример-использования)

# 🇺🇸 English

## BriefSurvey
Universal Dynamic Survey for Telegram Bots with `aiogram` version 3 `aiogram_dialog` and Pydantic
### Description
BriefSurvey is a module for quick and flexible creation of dialog-based surveys in Telegram using aiogram v3 and aiogram_dialog.

- Questions are defined using Pydantic models to enforce strong typing and validation.
- Final answers are automatically serialized back into a Pydantic result model.
- Easy to extend and customize.
- Supports different question types: text, number, single-choice, multiple-choice.
- Simple integration and handler registration.
- Auto-validation questions by names.Questions with names like "age", "weight" validate and send error messages automatically without validator enter.


---
## Installation
### Via pip 

```bash
pip install brief-survey
```
### From GitHub Repository

```bash
pip install git+https://github.com/Fugguri/brief_survey.git 
```
### Download Locally and Install

```bash
git clone https://github.com/Fugguri/brief_survey.git
pip install -e brief_survey 
```


## Quick Start
### (case 1) Dynamic crate a brief 
```python
from brief_survey import BriefSurvey
from brief_survey.validators.person import age
async def save_handler(user_id: int, result: any):
    # dynamic access to survey result fields by question name.
    name = result.name
    age = result.age
    gender = result.gender

    return

survey = BriefSurvey(
    save_handler=save_handler,
    start_command='start_brief'  # customizable start command for the survey
)

# Customizable error messages
survey.info_messages.invalid_input = "Invalid data received, please try again."
# Customizable button text at the end of the survey
survey.buttons.finish_text = "Finish survey"

survey.add_question(
    text="What is your name?",
    question_type="text",
    name="name",
    media_path='storage/media/img.png'  # you can send media with text for any question (optional)
)

survey.add_question(
    text="Your age?",
    question_type="number",
    name="age",
    validator=age # You can use validators from validators path of this lib.
)


survey.add_question(
    text="Select your gender",
    question_type="choice",
    name="gender",
    choices=["Male", "Female"],
    next_questions={
        'Male': "favorite_car",
        'Female': "favorite_color",
    }
)

survey.add_question(
    text="Favorite car brand?",
    question_type="choice",
    name="favorite_car",
    choices=["MBW", "Mercedes"],
    next_question='photo'  # mandatory parameter for queries depending on choice. If not set, proceeds to next survey question
)

survey.add_question(
    text="Favorite color?",
    question_type="choice",
    name="favorite_color",
    choices=["White", "Pink", "Black"],
    next_question='photo'  # mandatory parameter for queries depending on choice. If not set, proceeds to next survey question
)

survey.add_question(
    text="Upload your photo",
    question_type="photo",
    name="photo"
)

```
### (case 2) 1. Define your questions using Pydantic models:

```python
from brief_survey import QuestionBase, ChoiceQuestion, MultiChoiceQuestion

questions = [
    QuestionBase(
        name="name",
        text="What is your name?",
        type="text",
        validator=lambda x: bool(x.strip()),
    ),
    ChoiceQuestion(
        name="gender",
        text="Select your gender",
        type="choice",
        choices=[("1", "Male"), ("2", "Female")],
    ),
    MultiChoiceQuestion(
        name="profession",
        text="Select your profession",
        type="multi_choice",
        choices=[
            ("1", "Athlete"),
            ("2", "Entrepreneur"),
            ("3", "Worker"),
        ],
    ),
]

```
### 2. Define a result model:
``` python
from pydantic import BaseModel
from typing import Optional

class SurveyResult(BaseModel):
    name: Optional[str]
    gender: Optional[str]
    profession: Optional[list[str]]
```
### 3. Create a function to save results:
``` python
async def save_handler(user_id: int, result: SurveyResult):
    # Save logic, e.g., store in database
    print(f"User {user_id} survey result: {result}")

```
### 4. Initialize and register the survey:
``` python
from brief_survey import BriefSurvey

survey = BriefSurvey(
    questions=questions,
    save_handler=save_handler,
    result_model=SurveyResult,
)

# In your main bot file with Dispatcher dp
survey.register_handlers(
    dp=dp,
    command_start='start_survey',     # optional
    text='Start survey',               # optional
    callback_data="start_survey"       # optional
)
```
### 5. Launch the survey in Telegram with the command:
 /start_survey



## Important
If you have global handlers in your bot, filter states explicitly using StateFilter to avoid conflicts that can break the survey after the first message:
``` python
from aiogram.filters import StateFilter

dp.message.register(handle, StateFilter(None))          # Only outside states
dp.callback_query.register(handle_callback, StateFilter(None))
```
# Customizing Messages and Buttons in brief_survey

The **brief_survey** library provides `InfoMessages` and `InfoButtons` classes that allow you to easily customize system messages and button texts used in the survey dialogs.

## What can be customized (English)

### InfoMessages — system messages

| Field                   | Description                                       | Default example                  |
|-------------------------|-------------------------------------------------|---------------------------------|
| `invalid_input`          | Message shown when user input is invalid         | `"Please enter valid data."`    |
| `save_success`           | Message confirming data saved successfully       | `"Thank you! Data saved successfully."` |
| `save_fail`              | Message shown if saving data failed               | `"An error occurred during saving. Please try again later."` |
| `finish_text`            | Text displayed at survey completion               | `"Data received."`              |
| `question_not_found`     | Message shown if question is not found            | `"Error: question not found."`  |
| `pre_save_message`       | Message shown before saving data                   | `"Saving..."`                   |
| `start_message`          | Message shown at start of survey (optional)       | `None`                         |
| `forced_exit_message`    | Message shown when survey is forcefully exited    | `"Survey exited. Entered data does not allow continuation."` |

### InfoButtons — button labels

| Field                  | Description                                      | Default example                 |
|------------------------|-------------------------------------------------|--------------------------------|
| `finish_text`           | Text on the button to finish the survey          | `"Finish"`                    |
| `multi_select_confirm`  | Text for confirming multi-select choice          | `"Confirm selection"`          |
| `start_again`           | Text on the button to restart the survey         | `"Start again"`                |

## Example usage
``` python 
Setting system messages
survey.info_messages.invalid_input = "Invalid data received, please try again."
survey.info_messages.save_success = "Thank you! Your responses have been saved."
survey.info_messages.save_fail = "Saving failed, please try again later."
survey.info_messages.finish_text = "Thank you for participating!"
survey.info_messages.question_not_found = "Question not found."
survey.info_messages.pre_save_message = "Saving data..."
survey.info_messages.start_message = "Let's start the survey!"
survey.info_messages.forced_exit_message = "Survey terminated due to an error."

Setting button texts
survey.buttons.finish_text = "Finish survey"
survey.buttons.multi_select_confirm = "Confirm"
survey.buttons.start_again = "Restart"
```



# 🇷🇺 Русский

## BriefSurvey

Универсальный динамический опросник для Telegram-ботов на базе `aiogram_dialog` с поддержкой Pydantic-моделей вопросов и результатов.

---

## Описание

BriefSurvey — это модуль для быстрой и гибкой реализации диалоговых опросников в Telegram с помощью `aiogram` 3-й версии и `aiogram_dialog`.

- Вопросы описываются Pydantic-моделями для строгой типизации и валидации.
- Итоговые ответы автоматически сериализуются обратно в Pydantic-модель результата.
- Легко расширяется и настраивается.
- Позволяет реализовать опросник с разными типами вопросов: текст, число, выбор одного или нескольких вариантов.
- Простое подключение и регистрация обработчиков.
- Автоматическая валидация по имени вопроса. Поля типа "age", "weight" проходят автоматическую валидацию и присылают сообщение об ошибке, без указания валидаторов .

---

## Установка
### Github Repo
```bash
pip install git+https://github.com/Fugguri/brief_survey.git 
```
### Скачать локально и установить
```bash
git clone https://github.com/Fugguri/brief_survey.git
pip install -e brief_survey 
```


## Быстрый старт
### (1 вариант) Динамическое добавление вопросов
```python

from brief_survey import BriefSurvey
async def save_handler(user_id: int, result: any):
    #динамическое обращение к полям результата опроса по имени вопроса. 
    name = result.mame
    age = result.age
    gender = result.gender 
    return 
survey = BriefSurvey(
    save_handler=save_handler,
    start_command='start_brief' # Можно настраивать команду начала опроса
)

#Можно настраивать сообщения об ошибках
survey.info_messages.invalid_input = "Получены неверные данные, попробуйте еще раз"

#Можно настраивать сообщени и кнопку в конце опроса
survey.info_messages.invalid_input = "Получены неверные данные, попробуйте еще раз"
survey.buttons.finish_text = "Завершить опрос" 
# Если необходимо можете отправить сообщение перед началом опроса
survey.info_messages.start_message = 'Пройдите небольшой опрос перед началом работы с ботом.'
from brief_survey.validators.person import age  
survey.add_question(
    text="Как вас зовут?",
    question_type="text",
    name="name",
    media_path='storage/media/img.png'# Можете отправлять фотографии вместе с вопросом
)
survey.add_question(
    text="Ваш возраст?",
    question_type="number",
    name="age",
    validator=age # Вы можете использовать готовые валидаторы из раздела validators
)
survey.add_question(
    text="Выберите пол",
    question_type="choice",
    name="gender",
    choices=["Мужской", "Женский"],
    
    next_questions={
    'Мужской': "favorite_car",
    'Женский': "favorite_color",
    }
    
)
survey.add_question(
    text="Любимая марка автомобиля?",
    question_type="choice",
    name="favorite_car",
    choices=["MBW", "Mercedes"],
    next_question='photo' # Обязательный параметр для вариантов зависящих от выбора. Если не указать, пойдет дальше по опросу

)
survey.add_question(
    text="Любимый цвет?",
    question_type="choice",
    name="favorite_car",
    choices=["Белый", "Розовый", "Черный"],
    next_question='photo' # Обязательный параметр для вариантов зависящих от выбора. Если не указать, пойдет дальше по опросу
)

survey.add_question(
    text="Загрузите ваше фото",
    question_type="photo",
    name="photo"
)

````

### (2 вариант) 
1. Определите вопросы (используйте модели из основного модуля):

```python
from brief_survey import QuestionBase, ChoiceQuestion, MultiChoiceQuestion

questions = [
    QuestionBase(
        name="name",
        text="Как вас зовут?",
        type="text",
        validator=lambda x: bool(x.strip()),
    ),
    ChoiceQuestion(
        name="gender",
        text="Выберите пол",
        type="choice",
        choices=[("1", "Мужской"), ("2", "Женский")],
    ),
    MultiChoiceQuestion(
        name="gender",
        text="Выберите род деятельности",
        type="multi_choice",
        choices=[("1", "Спортсмен"), 
                 ("2", "Предприниматель"),
                 ("3", "Простой работник")
                 ],
    )
]



```
### 2. Определите модель результата:
``` python
from pydantic import BaseModel
from typing import Optional


class SurveyResult(BaseModel):
    name: Optional[str]
    gender: Optional[str]
```
### 3. Создайте функцию для сохранения результатов:
```python

async def save_handler(user_id: int, result: SurveyResult):
    # Логика сохранения, например, в базу
    print(f"Результат опроса пользователя {user_id}: {result}")
```
### 4. Инициализируйте и зарегистрируйте опросник:
``` python
from brief_survey import BriefSurvey

survey = BriefSurvey(
    questions=questions,
    save_handler=save_handler,
    result_model=SurveyResult,
)

# в основном файле с ботом (Dispatcher dp) регистрация в Dispatcher
survey.register_handlers(dp=dp,
                         command_start='start_survey', #опционально
                         text='Начать опрос', #опционально
                         callback_data="start_survey" #опционально
                         )
```
### 5.Запускайте команду в Telegram:

/start_survey

## Важно

Если у вас есть глобальный handler, фильтруйте state вручную, при помощи StateFilter.
Неясные конфликты и после первого сообщения опросник перестает работать.

``` python
from aiogram.filters import StateFilter
dp.message.register(handle,StateFilter(None))  # только вне состояний!
dp.callback_query.register(handle_callback,StateFilter(None))
```
## Настройка сообщений и кнопок в brief_survey

В библиотеке **brief_survey** доступны классы `InfoMessages` и `InfoButtons`, которые позволяют легко настраивать тексты системных сообщений и кнопок, используемых в диалогах опросника.

### Что можно настраивать

#### InfoMessages — системные сообщения

| Поле                    | Описание                                             | Пример по умолчанию                                  |
|-------------------------|-----------------------------------------------------|-----------------------------------------------------|
| `invalid_input`          | Сообщение при неверном вводе                         | `"Пожалуйста, введите корректные данные."`          |
| `save_success`           | Сообщение об успешном сохранении                     | `"Спасибо! Данные успешно сохранены."`              |
| `save_fail`              | Сообщение об ошибке при сохранении                   | `"Произошла ошибка при сохранении. Попробуйте позже."` |
| `finish_text`            | Текст при завершении опроса                          | `"Данные приняты."`                                  |
| `question_not_found`     | Сообщение при ошибке отсутствия вопроса              | `"Ошибка: вопрос не найден."`                        |
| `pre_save_message`       | Сообщение перед отправкой данных на сохранение       | `"Сохраняю"`                                         |
| `start_message`          | Сообщение при начале опроса (опционально)            | `None`                                              |
| `forced_exit_message`    | Сообщение при принудительном выходе из опроса        | `"Выход из опроса.Введенные данные не позволяют продолжить опрос"` |

#### InfoButtons — тексты кнопок

| Поле                   | Описание                                          | Пример по умолчанию               |
|------------------------|---------------------------------------------------|----------------------------------|
| `finish_text`           | Надпись на кнопке завершения опроса                | `"Завершить"`                    |
| `multi_select_confirm`  | Текст кнопки для подтверждения выбора (множественный выбор) | `"Подтвердить выбор"`            |
| `start_again`           | Текст кнопки для перезапуска опроса                 | `"Начать сначала"`               |

### Пример использования
``` python Настройка сообщений об ошибках и событий
survey.info_messages.invalid_input = "Получены неверные данные, попробуйте еще раз"
survey.info_messages.save_success = "Спасибо! Ваши ответы сохранены."
survey.info_messages.save_fail = "Ошибка при сохранении, попробуйте позже."
survey.info_messages.finish_text = "Спасибо за участие!"
survey.info_messages.question_not_found = "Вопрос не найден."
survey.info_messages.pre_save_message = "Данные сохраняются..."
survey.info_messages.start_message = "Начинаем опрос!"
survey.info_messages.forced_exit_message = "Опрос прерван из-за ошибки."

Настройка текстов кнопок
survey.buttons.finish_text = "Завершить опрос"
survey.buttons.multi_select_confirm = "Подтвердить"
survey.buttons.start_again = "Начать заново"
```



# ToDo
- add media list handler
- add 2 type logging 
- check same questions name in list
- add survey database saver. To save complete survey_to database. And call by his id
# for any errors send me a telegram message to [@fugguri](https://t/me/fugguri).
# ☕️bye me a coffe appreciated 

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Fugguri/brief_survey",
    "name": "brief-survey",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "aiogram3, aiogram, aiogram_dialog, brief",
    "author": "Fugguri",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/1b/a8/01b6a1e697e6dbdf1de0295f5d9d25552144f1c1a7cf3b6ee7c09339107e/brief_survey-0.2.8.2.tar.gz",
    "platform": null,
    "description": "# \u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435\n\n## \ud83c\uddfa\ud83c\uddf8 English\n\n- [BriefSurvey](#briefsurvey)\n- [Description](#description)\n- [Installation](#installation)\n  - [From GitHub Repository](#from-github-repository)\n  - [Download Locally and Install](#download-locally-and-install)\n- [Quick Start](#quick-start)\n  - [(case 1) Dynamic create a brief](#case-1-dynamic-crate-a-brief)\n  - [(case 2)](#case-2)\n    - [1. Define your questions using Pydantic models](#1-define-your-questions-using-pydantic-models)\n    - [2. Define a result model](#2-define-a-result-model)\n    - [3. Create a function to save results](#3-create-a-function-to-save-results)\n    - [4. Initialize and register the survey](#4-initialize-and-register-the-survey)\n    - [5. Launch the survey in Telegram with the command](#5-launch-the-survey-in-telegram-with-the-command)\n- [Important](#important)\n- [Customizing Messages and Buttons in brief_survey](#customizing-messages-and-buttons-in-brief_survey)\n  - [What can be customized (English)](#what-can-be-customized-english)\n    - [InfoMessages \u2014 system messages](#infomessages-\u2014-system-messages)\n    - [InfoButtons \u2014 button labels](#infobuttons-\u2014-button-labels)\n  - [Example usage](#example-usage)\n\n## \ud83c\uddf7\ud83c\uddfa \u0420\u0443\u0441\u0441\u043a\u0438\u0439\n\n- [BriefSurvey](#briefsurvey)\n- [\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435](#\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435)\n- [\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430](#\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430)\n  - [Github Repo](#github-repo)\n  - [\u0421\u043a\u0430\u0447\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c](#\u0441\u043a\u0430\u0447\u0430\u0442\u044c-\u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e-\u0438-\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c)\n- [\u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442](#\u0431\u044b\u0441\u0442\u0440\u044b\u0439-\u0441\u0442\u0430\u0440\u0442)\n  - [(1 \u0432\u0430\u0440\u0438\u0430\u043d\u0442) \u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432](#1-\u0432\u0430\u0440\u0438\u0430\u043d\u0442-\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0435-\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435-\u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432)\n  - [(2 \u0432\u0430\u0440\u0438\u0430\u043d\u0442)](#2-\u0432\u0430\u0440\u0438\u0430\u043d\u0442)\n    - [1. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b](#1-\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u0435-\u0432\u043e\u043f\u0440\u043e\u0441\u044b)\n    - [2. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u0435 \u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430](#2-\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u0435-\u043c\u043e\u0434\u0435\u043b\u044c-\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430)\n    - [3. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432](#3-\u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435-\u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0434\u043b\u044f-\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f-\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432)\n    - [4. \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u043e\u043f\u0440\u043e\u0441\u043d\u0438\u043a](#4-\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435-\u0438-\u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435-\u043e\u043f\u0440\u043e\u0441\u043d\u0438\u043a)\n    - [5. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0439\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0432 Telegram](#5\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0439\u0442\u0435-\u043a\u043e\u043c\u0430\u043d\u0434\u0443-\u0432-telegram)\n- [\u0412\u0430\u0436\u043d\u043e](#\u0432\u0430\u0436\u043d\u043e)\n- [\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u043a\u043d\u043e\u043f\u043e\u043a \u0432 brief_survey](#\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439-\u0438-\u043a\u043d\u043e\u043f\u043e\u043a-\u0432-brief_survey)\n  - [\u0427\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c](#\u0447\u0442\u043e-\u043c\u043e\u0436\u043d\u043e-\u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c)\n    - [InfoMessages \u2014 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f](#infomessages-\u2014-\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f)\n    - [InfoButtons \u2014 \u0442\u0435\u043a\u0441\u0442\u044b \u043a\u043d\u043e\u043f\u043e\u043a](#infobuttons-\u2014-\u0442\u0435\u043a\u0441\u0442\u044b-\u043a\u043d\u043e\u043f\u043e\u043a)\n  - [\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f](#\u043f\u0440\u0438\u043c\u0435\u0440-\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f)\n\n# \ud83c\uddfa\ud83c\uddf8 English\n\n## BriefSurvey\nUniversal Dynamic Survey for Telegram Bots with `aiogram` version 3 `aiogram_dialog` and Pydantic\n### Description\nBriefSurvey is a module for quick and flexible creation of dialog-based surveys in Telegram using aiogram v3 and aiogram_dialog.\n\n- Questions are defined using Pydantic models to enforce strong typing and validation.\n- Final answers are automatically serialized back into a Pydantic result model.\n- Easy to extend and customize.\n- Supports different question types: text, number, single-choice, multiple-choice.\n- Simple integration and handler registration.\n- Auto-validation questions by names.Questions with names like \"age\", \"weight\" validate and send error messages automatically without validator enter.\n\n\n---\n## Installation\n### Via pip \n\n```bash\npip install brief-survey\n```\n### From GitHub Repository\n\n```bash\npip install git+https://github.com/Fugguri/brief_survey.git \n```\n### Download Locally and Install\n\n```bash\ngit clone https://github.com/Fugguri/brief_survey.git\npip install -e brief_survey \n```\n\n\n## Quick Start\n### (case 1) Dynamic crate a brief \n```python\nfrom brief_survey import BriefSurvey\nfrom brief_survey.validators.person import age\nasync def save_handler(user_id: int, result: any):\n    # dynamic access to survey result fields by question name.\n    name = result.name\n    age = result.age\n    gender = result.gender\n\n    return\n\nsurvey = BriefSurvey(\n    save_handler=save_handler,\n    start_command='start_brief'  # customizable start command for the survey\n)\n\n# Customizable error messages\nsurvey.info_messages.invalid_input = \"Invalid data received, please try again.\"\n# Customizable button text at the end of the survey\nsurvey.buttons.finish_text = \"Finish survey\"\n\nsurvey.add_question(\n    text=\"What is your name?\",\n    question_type=\"text\",\n    name=\"name\",\n    media_path='storage/media/img.png'  # you can send media with text for any question (optional)\n)\n\nsurvey.add_question(\n    text=\"Your age?\",\n    question_type=\"number\",\n    name=\"age\",\n    validator=age # You can use validators from validators path of this lib.\n)\n\n\nsurvey.add_question(\n    text=\"Select your gender\",\n    question_type=\"choice\",\n    name=\"gender\",\n    choices=[\"Male\", \"Female\"],\n    next_questions={\n        'Male': \"favorite_car\",\n        'Female': \"favorite_color\",\n    }\n)\n\nsurvey.add_question(\n    text=\"Favorite car brand?\",\n    question_type=\"choice\",\n    name=\"favorite_car\",\n    choices=[\"MBW\", \"Mercedes\"],\n    next_question='photo'  # mandatory parameter for queries depending on choice. If not set, proceeds to next survey question\n)\n\nsurvey.add_question(\n    text=\"Favorite color?\",\n    question_type=\"choice\",\n    name=\"favorite_color\",\n    choices=[\"White\", \"Pink\", \"Black\"],\n    next_question='photo'  # mandatory parameter for queries depending on choice. If not set, proceeds to next survey question\n)\n\nsurvey.add_question(\n    text=\"Upload your photo\",\n    question_type=\"photo\",\n    name=\"photo\"\n)\n\n```\n### (case 2) 1. Define your questions using Pydantic models:\n\n```python\nfrom brief_survey import QuestionBase, ChoiceQuestion, MultiChoiceQuestion\n\nquestions = [\n    QuestionBase(\n        name=\"name\",\n        text=\"What is your name?\",\n        type=\"text\",\n        validator=lambda x: bool(x.strip()),\n    ),\n    ChoiceQuestion(\n        name=\"gender\",\n        text=\"Select your gender\",\n        type=\"choice\",\n        choices=[(\"1\", \"Male\"), (\"2\", \"Female\")],\n    ),\n    MultiChoiceQuestion(\n        name=\"profession\",\n        text=\"Select your profession\",\n        type=\"multi_choice\",\n        choices=[\n            (\"1\", \"Athlete\"),\n            (\"2\", \"Entrepreneur\"),\n            (\"3\", \"Worker\"),\n        ],\n    ),\n]\n\n```\n### 2. Define a result model:\n``` python\nfrom pydantic import BaseModel\nfrom typing import Optional\n\nclass SurveyResult(BaseModel):\n    name: Optional[str]\n    gender: Optional[str]\n    profession: Optional[list[str]]\n```\n### 3. Create a function to save results:\n``` python\nasync def save_handler(user_id: int, result: SurveyResult):\n    # Save logic, e.g., store in database\n    print(f\"User {user_id} survey result: {result}\")\n\n```\n### 4. Initialize and register the survey:\n``` python\nfrom brief_survey import BriefSurvey\n\nsurvey = BriefSurvey(\n    questions=questions,\n    save_handler=save_handler,\n    result_model=SurveyResult,\n)\n\n# In your main bot file with Dispatcher dp\nsurvey.register_handlers(\n    dp=dp,\n    command_start='start_survey',     # optional\n    text='Start survey',               # optional\n    callback_data=\"start_survey\"       # optional\n)\n```\n### 5. Launch the survey in Telegram with the command:\n /start_survey\n\n\n\n## Important\nIf you have global handlers in your bot, filter states explicitly using StateFilter to avoid conflicts that can break the survey after the first message:\n``` python\nfrom aiogram.filters import StateFilter\n\ndp.message.register(handle, StateFilter(None))          # Only outside states\ndp.callback_query.register(handle_callback, StateFilter(None))\n```\n# Customizing Messages and Buttons in brief_survey\n\nThe **brief_survey** library provides `InfoMessages` and `InfoButtons` classes that allow you to easily customize system messages and button texts used in the survey dialogs.\n\n## What can be customized (English)\n\n### InfoMessages \u2014 system messages\n\n| Field                   | Description                                       | Default example                  |\n|-------------------------|-------------------------------------------------|---------------------------------|\n| `invalid_input`          | Message shown when user input is invalid         | `\"Please enter valid data.\"`    |\n| `save_success`           | Message confirming data saved successfully       | `\"Thank you! Data saved successfully.\"` |\n| `save_fail`              | Message shown if saving data failed               | `\"An error occurred during saving. Please try again later.\"` |\n| `finish_text`            | Text displayed at survey completion               | `\"Data received.\"`              |\n| `question_not_found`     | Message shown if question is not found            | `\"Error: question not found.\"`  |\n| `pre_save_message`       | Message shown before saving data                   | `\"Saving...\"`                   |\n| `start_message`          | Message shown at start of survey (optional)       | `None`                         |\n| `forced_exit_message`    | Message shown when survey is forcefully exited    | `\"Survey exited. Entered data does not allow continuation.\"` |\n\n### InfoButtons \u2014 button labels\n\n| Field                  | Description                                      | Default example                 |\n|------------------------|-------------------------------------------------|--------------------------------|\n| `finish_text`           | Text on the button to finish the survey          | `\"Finish\"`                    |\n| `multi_select_confirm`  | Text for confirming multi-select choice          | `\"Confirm selection\"`          |\n| `start_again`           | Text on the button to restart the survey         | `\"Start again\"`                |\n\n## Example usage\n``` python \nSetting system messages\nsurvey.info_messages.invalid_input = \"Invalid data received, please try again.\"\nsurvey.info_messages.save_success = \"Thank you! Your responses have been saved.\"\nsurvey.info_messages.save_fail = \"Saving failed, please try again later.\"\nsurvey.info_messages.finish_text = \"Thank you for participating!\"\nsurvey.info_messages.question_not_found = \"Question not found.\"\nsurvey.info_messages.pre_save_message = \"Saving data...\"\nsurvey.info_messages.start_message = \"Let's start the survey!\"\nsurvey.info_messages.forced_exit_message = \"Survey terminated due to an error.\"\n\nSetting button texts\nsurvey.buttons.finish_text = \"Finish survey\"\nsurvey.buttons.multi_select_confirm = \"Confirm\"\nsurvey.buttons.start_again = \"Restart\"\n```\n\n\n\n# \ud83c\uddf7\ud83c\uddfa \u0420\u0443\u0441\u0441\u043a\u0438\u0439\n\n## BriefSurvey\n\n\u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043e\u043f\u0440\u043e\u0441\u043d\u0438\u043a \u0434\u043b\u044f Telegram-\u0431\u043e\u0442\u043e\u0432 \u043d\u0430 \u0431\u0430\u0437\u0435 `aiogram_dialog` \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 Pydantic-\u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432.\n\n---\n\n## \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\n\nBriefSurvey \u2014 \u044d\u0442\u043e \u043c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0439 \u0438 \u0433\u0438\u0431\u043a\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u044b\u0445 \u043e\u043f\u0440\u043e\u0441\u043d\u0438\u043a\u043e\u0432 \u0432 Telegram \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e `aiogram` 3-\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0438 `aiogram_dialog`.\n\n- \u0412\u043e\u043f\u0440\u043e\u0441\u044b \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f Pydantic-\u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u0433\u043e\u0439 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438.\n- \u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 Pydantic-\u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430.\n- \u041b\u0435\u0433\u043a\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442\u0441\u044f \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f.\n- \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0440\u043e\u0441\u043d\u0438\u043a \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432: \u0442\u0435\u043a\u0441\u0442, \u0447\u0438\u0441\u043b\u043e, \u0432\u044b\u0431\u043e\u0440 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432.\n- \u041f\u0440\u043e\u0441\u0442\u043e\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432.\n- \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043f\u043e \u0438\u043c\u0435\u043d\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u0430. \u041f\u043e\u043b\u044f \u0442\u0438\u043f\u0430 \"age\", \"weight\" \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0438 \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u044e\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435, \u0431\u0435\u0437 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u043e\u0432 .\n\n---\n\n## \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\n### Github Repo\n```bash\npip install git+https://github.com/Fugguri/brief_survey.git \n```\n### \u0421\u043a\u0430\u0447\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\n```bash\ngit clone https://github.com/Fugguri/brief_survey.git\npip install -e brief_survey \n```\n\n\n## \u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\n### (1 \u0432\u0430\u0440\u0438\u0430\u043d\u0442) \u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432\n```python\n\nfrom brief_survey import BriefSurvey\nasync def save_handler(user_id: int, result: any):\n    #\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u043f\u043e\u043b\u044f\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043e\u043f\u0440\u043e\u0441\u0430 \u043f\u043e \u0438\u043c\u0435\u043d\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u0430. \n    name = result.mame\n    age = result.age\n    gender = result.gender \n    return \nsurvey = BriefSurvey(\n    save_handler=save_handler,\n    start_command='start_brief' # \u041c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u043e\u0441\u0430\n)\n\n#\u041c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445\nsurvey.info_messages.invalid_input = \"\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437\"\n\n#\u041c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438 \u0438 \u043a\u043d\u043e\u043f\u043a\u0443 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043e\u043f\u0440\u043e\u0441\u0430\nsurvey.info_messages.invalid_input = \"\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437\"\nsurvey.buttons.finish_text = \"\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043e\u043f\u0440\u043e\u0441\" \n# \u0415\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u043e\u043f\u0440\u043e\u0441\u0430\nsurvey.info_messages.start_message = '\u041f\u0440\u043e\u0439\u0434\u0438\u0442\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043e\u043f\u0440\u043e\u0441 \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u043e\u0442\u043e\u043c.'\nfrom brief_survey.validators.person import age  \nsurvey.add_question(\n    text=\"\u041a\u0430\u043a \u0432\u0430\u0441 \u0437\u043e\u0432\u0443\u0442?\",\n    question_type=\"text\",\n    name=\"name\",\n    media_path='storage/media/img.png'# \u041c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u043c\n)\nsurvey.add_question(\n    text=\"\u0412\u0430\u0448 \u0432\u043e\u0437\u0440\u0430\u0441\u0442?\",\n    question_type=\"number\",\n    name=\"age\",\n    validator=age # \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u044b \u0438\u0437 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 validators\n)\nsurvey.add_question(\n    text=\"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u043e\u043b\",\n    question_type=\"choice\",\n    name=\"gender\",\n    choices=[\"\u041c\u0443\u0436\u0441\u043a\u043e\u0439\", \"\u0416\u0435\u043d\u0441\u043a\u0438\u0439\"],\n    \n    next_questions={\n    '\u041c\u0443\u0436\u0441\u043a\u043e\u0439': \"favorite_car\",\n    '\u0416\u0435\u043d\u0441\u043a\u0438\u0439': \"favorite_color\",\n    }\n    \n)\nsurvey.add_question(\n    text=\"\u041b\u044e\u0431\u0438\u043c\u0430\u044f \u043c\u0430\u0440\u043a\u0430 \u0430\u0432\u0442\u043e\u043c\u043e\u0431\u0438\u043b\u044f?\",\n    question_type=\"choice\",\n    name=\"favorite_car\",\n    choices=[\"MBW\", \"Mercedes\"],\n    next_question='photo' # \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0434\u043b\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u0445 \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430. \u0415\u0441\u043b\u0438 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043f\u043e\u0439\u0434\u0435\u0442 \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u043e \u043e\u043f\u0440\u043e\u0441\u0443\n\n)\nsurvey.add_question(\n    text=\"\u041b\u044e\u0431\u0438\u043c\u044b\u0439 \u0446\u0432\u0435\u0442?\",\n    question_type=\"choice\",\n    name=\"favorite_car\",\n    choices=[\"\u0411\u0435\u043b\u044b\u0439\", \"\u0420\u043e\u0437\u043e\u0432\u044b\u0439\", \"\u0427\u0435\u0440\u043d\u044b\u0439\"],\n    next_question='photo' # \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0434\u043b\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u0445 \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430. \u0415\u0441\u043b\u0438 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043f\u043e\u0439\u0434\u0435\u0442 \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u043e \u043e\u043f\u0440\u043e\u0441\u0443\n)\n\nsurvey.add_question(\n    text=\"\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0432\u0430\u0448\u0435 \u0444\u043e\u0442\u043e\",\n    question_type=\"photo\",\n    name=\"photo\"\n)\n\n````\n\n### (2 \u0432\u0430\u0440\u0438\u0430\u043d\u0442) \n1. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f):\n\n```python\nfrom brief_survey import QuestionBase, ChoiceQuestion, MultiChoiceQuestion\n\nquestions = [\n    QuestionBase(\n        name=\"name\",\n        text=\"\u041a\u0430\u043a \u0432\u0430\u0441 \u0437\u043e\u0432\u0443\u0442?\",\n        type=\"text\",\n        validator=lambda x: bool(x.strip()),\n    ),\n    ChoiceQuestion(\n        name=\"gender\",\n        text=\"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u043e\u043b\",\n        type=\"choice\",\n        choices=[(\"1\", \"\u041c\u0443\u0436\u0441\u043a\u043e\u0439\"), (\"2\", \"\u0416\u0435\u043d\u0441\u043a\u0438\u0439\")],\n    ),\n    MultiChoiceQuestion(\n        name=\"gender\",\n        text=\"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u043e\u0434 \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438\",\n        type=\"multi_choice\",\n        choices=[(\"1\", \"\u0421\u043f\u043e\u0440\u0442\u0441\u043c\u0435\u043d\"), \n                 (\"2\", \"\u041f\u0440\u0435\u0434\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\"),\n                 (\"3\", \"\u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u043d\u0438\u043a\")\n                 ],\n    )\n]\n\n\n\n```\n### 2. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u0435 \u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430:\n``` python\nfrom pydantic import BaseModel\nfrom typing import Optional\n\n\nclass SurveyResult(BaseModel):\n    name: Optional[str]\n    gender: Optional[str]\n```\n### 3. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432:\n```python\n\nasync def save_handler(user_id: int, result: SurveyResult):\n    # \u041b\u043e\u0433\u0438\u043a\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0431\u0430\u0437\u0443\n    print(f\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u043f\u0440\u043e\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f {user_id}: {result}\")\n```\n### 4. \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u043e\u043f\u0440\u043e\u0441\u043d\u0438\u043a:\n``` python\nfrom brief_survey import BriefSurvey\n\nsurvey = BriefSurvey(\n    questions=questions,\n    save_handler=save_handler,\n    result_model=SurveyResult,\n)\n\n# \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0441 \u0431\u043e\u0442\u043e\u043c (Dispatcher dp) \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0432 Dispatcher\nsurvey.register_handlers(dp=dp,\n                         command_start='start_survey', #\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\n                         text='\u041d\u0430\u0447\u0430\u0442\u044c \u043e\u043f\u0440\u043e\u0441', #\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\n                         callback_data=\"start_survey\" #\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\n                         )\n```\n### 5.\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0439\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0432 Telegram:\n\n/start_survey\n\n## \u0412\u0430\u0436\u043d\u043e\n\n\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 handler, \u0444\u0438\u043b\u044c\u0442\u0440\u0443\u0439\u0442\u0435 state \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 StateFilter.\n\u041d\u0435\u044f\u0441\u043d\u044b\u0435 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u044b \u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u043f\u0440\u043e\u0441\u043d\u0438\u043a \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.\n\n``` python\nfrom aiogram.filters import StateFilter\ndp.message.register(handle,StateFilter(None))  # \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439!\ndp.callback_query.register(handle_callback,StateFilter(None))\n```\n## \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u043a\u043d\u043e\u043f\u043e\u043a \u0432 brief_survey\n\n\u0412 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 **brief_survey** \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043a\u043b\u0430\u0441\u0441\u044b `InfoMessages` \u0438 `InfoButtons`, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043b\u0435\u0433\u043a\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u043a\u043d\u043e\u043f\u043e\u043a, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u0430\u0445 \u043e\u043f\u0440\u043e\u0441\u043d\u0438\u043a\u0430.\n\n### \u0427\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c\n\n#### InfoMessages \u2014 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\n\n| \u041f\u043e\u043b\u0435                    | \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435                                             | \u041f\u0440\u0438\u043c\u0435\u0440 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e                                  |\n|-------------------------|-----------------------------------------------------|-----------------------------------------------------|\n| `invalid_input`          | \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u043c \u0432\u0432\u043e\u0434\u0435                         | `\"\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.\"`          |\n| `save_success`           | \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438                     | `\"\u0421\u043f\u0430\u0441\u0438\u0431\u043e! \u0414\u0430\u043d\u043d\u044b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b.\"`              |\n| `save_fail`              | \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438                   | `\"\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u043e\u0437\u0436\u0435.\"` |\n| `finish_text`            | \u0422\u0435\u043a\u0441\u0442 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043e\u043f\u0440\u043e\u0441\u0430                          | `\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043d\u044f\u0442\u044b.\"`                                  |\n| `question_not_found`     | \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u0430              | `\"\u041e\u0448\u0438\u0431\u043a\u0430: \u0432\u043e\u043f\u0440\u043e\u0441 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d.\"`                        |\n| `pre_save_message`       | \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0434 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435       | `\"\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u044e\"`                                         |\n| `start_message`          | \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u043d\u0430\u0447\u0430\u043b\u0435 \u043e\u043f\u0440\u043e\u0441\u0430 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e)            | `None`                                              |\n| `forced_exit_message`    | \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u0432\u044b\u0445\u043e\u0434\u0435 \u0438\u0437 \u043e\u043f\u0440\u043e\u0441\u0430        | `\"\u0412\u044b\u0445\u043e\u0434 \u0438\u0437 \u043e\u043f\u0440\u043e\u0441\u0430.\u0412\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u043e\u043f\u0440\u043e\u0441\"` |\n\n#### InfoButtons \u2014 \u0442\u0435\u043a\u0441\u0442\u044b \u043a\u043d\u043e\u043f\u043e\u043a\n\n| \u041f\u043e\u043b\u0435                   | \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435                                          | \u041f\u0440\u0438\u043c\u0435\u0440 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e               |\n|------------------------|---------------------------------------------------|----------------------------------|\n| `finish_text`           | \u041d\u0430\u0434\u043f\u0438\u0441\u044c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043e\u043f\u0440\u043e\u0441\u0430                | `\"\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c\"`                    |\n| `multi_select_confirm`  | \u0422\u0435\u043a\u0441\u0442 \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u043b\u044f \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0432\u044b\u0431\u043e\u0440\u0430 (\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440) | `\"\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c \u0432\u044b\u0431\u043e\u0440\"`            |\n| `start_again`           | \u0422\u0435\u043a\u0441\u0442 \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043e\u043f\u0440\u043e\u0441\u0430                 | `\"\u041d\u0430\u0447\u0430\u0442\u044c \u0441\u043d\u0430\u0447\u0430\u043b\u0430\"`               |\n\n### \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\n``` python \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\nsurvey.info_messages.invalid_input = \"\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437\"\nsurvey.info_messages.save_success = \"\u0421\u043f\u0430\u0441\u0438\u0431\u043e! \u0412\u0430\u0448\u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b.\"\nsurvey.info_messages.save_fail = \"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u043e\u0437\u0436\u0435.\"\nsurvey.info_messages.finish_text = \"\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0443\u0447\u0430\u0441\u0442\u0438\u0435!\"\nsurvey.info_messages.question_not_found = \"\u0412\u043e\u043f\u0440\u043e\u0441 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d.\"\nsurvey.info_messages.pre_save_message = \"\u0414\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f...\"\nsurvey.info_messages.start_message = \"\u041d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043e\u043f\u0440\u043e\u0441!\"\nsurvey.info_messages.forced_exit_message = \"\u041e\u043f\u0440\u043e\u0441 \u043f\u0440\u0435\u0440\u0432\u0430\u043d \u0438\u0437-\u0437\u0430 \u043e\u0448\u0438\u0431\u043a\u0438.\"\n\n\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u043a\u043d\u043e\u043f\u043e\u043a\nsurvey.buttons.finish_text = \"\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043e\u043f\u0440\u043e\u0441\"\nsurvey.buttons.multi_select_confirm = \"\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c\"\nsurvey.buttons.start_again = \"\u041d\u0430\u0447\u0430\u0442\u044c \u0437\u0430\u043d\u043e\u0432\u043e\"\n```\n\n\n\n# ToDo\n- add media list handler\n- add 2 type logging \n- check same questions name in list\n- add survey database saver. To save complete survey_to database. And call by his id\n# for any errors send me a telegram message to [@fugguri](https://t/me/fugguri).\n# \u2615\ufe0fbye me a coffe appreciated \n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Dynamic survey/dialog for aiogram3  with aiogram_dialog and Pydantic support",
    "version": "0.2.8.2",
    "project_urls": {
        "Homepage": "https://github.com/Fugguri/brief_survey",
        "github": "https://github.com/Fugguri/brief_survey",
        "pypi": "https://pypi.org/project/brief-survey/"
    },
    "split_keywords": [
        "aiogram3",
        " aiogram",
        " aiogram_dialog",
        " brief"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fe9263b150d5ca0600dc889ac2096184ac282d18f1c3cf4b37eef16263848a65",
                "md5": "e7ce7816b97b8646d14e98312b4cfc75",
                "sha256": "5b0ffae141dc86e1e3e70590f7f0d2faf8eb6f14569c65a0eaf84f734188c62d"
            },
            "downloads": -1,
            "filename": "brief_survey-0.2.8.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e7ce7816b97b8646d14e98312b4cfc75",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 30534,
            "upload_time": "2025-08-13T10:35:57",
            "upload_time_iso_8601": "2025-08-13T10:35:57.262823Z",
            "url": "https://files.pythonhosted.org/packages/fe/92/63b150d5ca0600dc889ac2096184ac282d18f1c3cf4b37eef16263848a65/brief_survey-0.2.8.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1ba801b6a1e697e6dbdf1de0295f5d9d25552144f1c1a7cf3b6ee7c09339107e",
                "md5": "a53fedc90b75ac328e5c5c2a0f7c2ca4",
                "sha256": "da7193e8bef72f1fb9bb0b4abf8c27fcd7e26767b4afb83e12a31ac138c63061"
            },
            "downloads": -1,
            "filename": "brief_survey-0.2.8.2.tar.gz",
            "has_sig": false,
            "md5_digest": "a53fedc90b75ac328e5c5c2a0f7c2ca4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 30727,
            "upload_time": "2025-08-13T10:35:58",
            "upload_time_iso_8601": "2025-08-13T10:35:58.287458Z",
            "url": "https://files.pythonhosted.org/packages/1b/a8/01b6a1e697e6dbdf1de0295f5d9d25552144f1c1a7cf3b6ee7c09339107e/brief_survey-0.2.8.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-13 10:35:58",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Fugguri",
    "github_project": "brief_survey",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "aiogram",
            "specs": [
                [
                    "==",
                    "3.21.0"
                ]
            ]
        },
        {
            "name": "aiogram_dialog",
            "specs": [
                [
                    "==",
                    "2.3.1"
                ]
            ]
        },
        {
            "name": "phonenumbers",
            "specs": [
                [
                    "==",
                    "9.0.10"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    "==",
                    "2.11.7"
                ]
            ]
        },
        {
            "name": "setuptools",
            "specs": [
                [
                    "==",
                    "68.0.0"
                ]
            ]
        }
    ],
    "lcname": "brief-survey"
}
        
Elapsed time: 0.65672s