aiostep


Nameaiostep JSON
Version 0.3.4 PyPI version JSON
download
home_pageNone
SummaryA Python library to handle steps in aiogram framework.
upload_time2025-01-26 17:29:26
maintainerNone
docs_urlNone
authorNasrollah Yusefi
requires_python<4.0,>=3.9
licenseMIT
keywords aiogram steps states telegram bot asynchronous aiostep
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![PyPI Version](https://img.shields.io/pypi/v/aiostep)
![Python Version](https://img.shields.io/pypi/pyversions/aiostep)
![License](https://img.shields.io/pypi/l/aiostep)
![Total Downloads](https://static.pepy.tech/badge/aiostep)
![Downloads](https://img.shields.io/pypi/dm/aiostep)
[![Telegram](https://img.shields.io/badge/Telegram-Join%20Chat-blue?logo=telegram&style=flat-square)](https://t.me/aiostep_chat)


# Aiostep - Simple and Flexible State Management

Aiostep is a lightweight and flexible state management tool designed for Telegram bots and similar applications. It allows developers to track user states and manage transitions between them with ease. Whether you're building a multi-step form, handling complex user interactions, or simply need to store temporary user data, Aiostep makes it straightforward.

_We have a vibrant community of developers helping each other in our_ **[Telegram group](https://t.me/aiostep_chat)**. _Join us!_
_Stay tuned for library updates and new releases on our_ **[Telegram Channel](https://t.me/aiostep)**.

---

## Features

- **Simple API**: Intuitive methods for setting, getting, and deleting user states and associated data.
- **Customizable Storage**: Use in-memory storage or integrate with persistent options like Redis or file-based storage.
- **Direct User Interaction**: Easily ask questions and receive user responses directly within handlers, reducing boilerplate code.
- **Extendable**: Designed to integrate with existing frameworks such as aiogram.

---

## How It Works

### User Interaction Methods

Aiostep provides three primary methods for interacting with users and managing multi-step processes:

1. **`wait_for`**:
   - Use this method to wait for a specific user response within the current handler.
   - Simplifies user interaction by reducing the need for separate handlers.

2. **`register_next_step`**:
   - Allows registering the next handler explicitly for a user.
   - Useful for chaining steps in a process.

3. **States**:
   - Define user states to manage stages in a multi-step workflow.
   - States can include optional callbacks for seamless navigation between steps.

---

## Installation

To start using Aiostep, simply install it via pip.

```bash
pip install --upgrade aiostep
```

If you want use `RedisStateStorage`, you should install aiostep with redis support:
```bash
pip install --upgrade aiostep[redis]
```

---

## Usage

### Using `wait_for` and `register_next_step`
**Aiostep offers two primary methods for managing direct user interactions:**

#### 1. `wait_for`:
- This method allows you to wait for a user response directly within the current handler.
- Requires the `Listen` middleware to be set up for intercepting subsequent user messages.

**Example:**
```python
from aiostep import Listen, wait_for
from aiogram import Dispatcher

dp = Dispatcher()
dp.message.outer_middleware(Listen())

@dp.message_handler(commands=["start"])
async def ask_question(message: Message):
    await message.reply("Please type something:")
    try:
        response = await wait_for(message.from_user.id, timeout=25)  # timeout is optional
    except TimeoutError:
        await message.reply("You took too long to answer.")
    else:
        await message.reply(f"You typed: {response.text}")
```
> [!NOTE]\
> The `timeout` parameter is optional; if not provided, the bot will wait indefinitely for a response.

#### 2. `register_next_step`
- Use this method to explicitly register the next handler for the user's response.
- Also requires the `Listen` middleware for processing follow-up messages.

**Example:**

```python
@dp.message_handler(commands=["start"])
async def ask_question(message: Message):
    await aiostep.register_next_step(message.chat.id, handle_answer)
    await message.reply("What's your name?")

async def handle_answer(message: Message):
    await message.reply(f"Hello, {message.text}!")
```

### Using States
**Aiostep supports managing user states to handle multi-step workflows. Unlike the previous methods, managing states does not require the `Listen` middleware.**


#### 1. Memory State Storage:
- This is an in-memory implementation suitable for temporary state storage.

**Example:**

```python
from aiostep import MemoryStateStorage

state_manager = MemoryStateStorage()

@dp.message_handler(commands=["start"])
async def start_process(message: Message):
    state_manager.set_state(
        user_id=message.from_user.id,
        state="STEP_ONE"
    )
    await message.reply("State set to STEP_ONE!")

@dp.message_handler(lambda message: state_manager.get_state(message.from_user.id).current_state == "STEP_ONE")
async def handle_step_one(message: Message):
    await message.reply("You're in STEP_ONE.")
```

**Returning to Previous State:**
```python
@dp.message_handler(lambda message: message.text == "Back")
async def go_back(message: Message):
    step = state_manager.get_state(message.from_user.id)
    if step and step.callback:
        await step.callback(message)
    else:
        await message.reply("No previous state found.")
```
> [!NOTE]\
> You should manually use getattr to find and call the back step handler if you use `RedisStateStorage` or `FileStateStorage`, because callbacks are saved as strings (function name)
>```python
>@dp.message_handler(lambda message: message.text == "Back")
>async def go_back(message: Message):
>    step = await state_manager.get_state(message.from_user.id)
>    if step and step.callback:
>        callback = getattr(step.callback)
>        await callback(message)
>    else:
>        await message.reply("No previous state found.")
>```

#### 2. Other Storage Options:
- File-based and Redis storage implementations are also available, providing similar functionality with persistent data storage.
- Simply replace MemoryStateStorage with FileStateStorage or RedisStateStorage when initializing the state manager.
> [!NOTE]\
> Methods in `MemoryStateStorage`, `FileStateStorage` and `RedisStateStorage` are synchronous.
> **If you want use asynchronous versions, use `aiostep.asyncio`:**
> ```python
> from aiostep.asyncio import AsyncMemoryStateStorage
> from aiostep.asyncio import AsyncFileStateStorage
> from aiostep.asyncio import AsyncRedisStateStorage
> ```

#### 3. Timeout States

To set a timeout (expiry) for the state storage, you can use the `ex` argument for both `RedisStateStorage` and `FileStateStorage`.
But for `MemoryStateStorage` you need to pass a TTLCache if you want set timeout.

Here's how you can set it up:

- **For `MemoryStateStorage`** (using `cachebox.TTLCache`):

    ```python
    from aiostep import MemoryStateStorage
    from cachebox import TTLCache  # cachetools.TTLCache also works

    # Create a TTLCache with a timeout of 200 seconds
    storage = MemoryStateStorage(TTLCache(0, 200))  # Timeout is 200 seconds
    ```

- **For `RedisStateStorage`** (using the `ex` argument for expiry time):

    ```python
    from aiostep import RedisStateStorage
    from aiostep import FileStateStorage

    # Create RedisStateStorage with a timeout of 200 seconds
    storage = RedisStateStorage(db=0, ex=200)  # Timeout (expiry) is 200 seconds
    storage = FileStateStorage("path.txt", ex=200)  # Same as RedisStateStorage
    ```
In both cases, the state will automatically expire after the specified time, and the data will be removed from the storage.

---

### Using Data

#### Setting Data

```python
state_manager.set_data(
    user_id=message.from_user.id,
    data={"key": "value"}
)
```

#### Getting Data

```python
data = state_manager.get_data(user_id=message.from_user.id)
await message.reply(f"Your data: {data}")
```

---

## Important Notes

1. **Callbacks**:
   - Callbacks can be any callable object, such as functions.
   - In `FileStateStorage` and `RedisStateStorage` they are stored as strings (e.g. function name).

3. **Storage Flexibility**:
   - The memory-based implementation is ideal for development and testing.
   - Persistent storage like Redis is recommended for production.

---

## Future Plans

- **Better Library Compatibility**: Enhanced support for other Telegram bot libraries such as `pyTelegramBotAPI` and `python-telegram-bot`, in addition to `aiogram`.
- **Improved Documentation**: Detailed guides and best practices.

---

## License

This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.

---

For more information or to contribute, visit our [GitHub repository](#).

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "aiostep",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.9",
    "maintainer_email": null,
    "keywords": "aiogram, steps, states, Telegram bot, asynchronous, aiostep",
    "author": "Nasrollah Yusefi",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/2f/7d/847f5eafe02bce39a1236845ccc29d7d12ccaaaccc028892fb274c493c90/aiostep-0.3.4.tar.gz",
    "platform": null,
    "description": "![PyPI Version](https://img.shields.io/pypi/v/aiostep)\n![Python Version](https://img.shields.io/pypi/pyversions/aiostep)\n![License](https://img.shields.io/pypi/l/aiostep)\n![Total Downloads](https://static.pepy.tech/badge/aiostep)\n![Downloads](https://img.shields.io/pypi/dm/aiostep)\n[![Telegram](https://img.shields.io/badge/Telegram-Join%20Chat-blue?logo=telegram&style=flat-square)](https://t.me/aiostep_chat)\n\n\n# Aiostep - Simple and Flexible State Management\n\nAiostep is a lightweight and flexible state management tool designed for Telegram bots and similar applications. It allows developers to track user states and manage transitions between them with ease. Whether you're building a multi-step form, handling complex user interactions, or simply need to store temporary user data, Aiostep makes it straightforward.\n\n_We have a vibrant community of developers helping each other in our_ **[Telegram group](https://t.me/aiostep_chat)**. _Join us!_\n_Stay tuned for library updates and new releases on our_ **[Telegram Channel](https://t.me/aiostep)**.\n\n---\n\n## Features\n\n- **Simple API**: Intuitive methods for setting, getting, and deleting user states and associated data.\n- **Customizable Storage**: Use in-memory storage or integrate with persistent options like Redis or file-based storage.\n- **Direct User Interaction**: Easily ask questions and receive user responses directly within handlers, reducing boilerplate code.\n- **Extendable**: Designed to integrate with existing frameworks such as aiogram.\n\n---\n\n## How It Works\n\n### User Interaction Methods\n\nAiostep provides three primary methods for interacting with users and managing multi-step processes:\n\n1. **`wait_for`**:\n   - Use this method to wait for a specific user response within the current handler.\n   - Simplifies user interaction by reducing the need for separate handlers.\n\n2. **`register_next_step`**:\n   - Allows registering the next handler explicitly for a user.\n   - Useful for chaining steps in a process.\n\n3. **States**:\n   - Define user states to manage stages in a multi-step workflow.\n   - States can include optional callbacks for seamless navigation between steps.\n\n---\n\n## Installation\n\nTo start using Aiostep, simply install it via pip.\n\n```bash\npip install --upgrade aiostep\n```\n\nIf you want use `RedisStateStorage`, you should install aiostep with redis support:\n```bash\npip install --upgrade aiostep[redis]\n```\n\n---\n\n## Usage\n\n### Using `wait_for` and `register_next_step`\n**Aiostep offers two primary methods for managing direct user interactions:**\n\n#### 1. `wait_for`:\n- This method allows you to wait for a user response directly within the current handler.\n- Requires the `Listen` middleware to be set up for intercepting subsequent user messages.\n\n**Example:**\n```python\nfrom aiostep import Listen, wait_for\nfrom aiogram import Dispatcher\n\ndp = Dispatcher()\ndp.message.outer_middleware(Listen())\n\n@dp.message_handler(commands=[\"start\"])\nasync def ask_question(message: Message):\n    await message.reply(\"Please type something:\")\n    try:\n        response = await wait_for(message.from_user.id, timeout=25)  # timeout is optional\n    except TimeoutError:\n        await message.reply(\"You took too long to answer.\")\n    else:\n        await message.reply(f\"You typed: {response.text}\")\n```\n> [!NOTE]\\\n> The `timeout` parameter is optional; if not provided, the bot will wait indefinitely for a response.\n\n#### 2. `register_next_step`\n- Use this method to explicitly register the next handler for the user's response.\n- Also requires the `Listen` middleware for processing follow-up messages.\n\n**Example:**\n\n```python\n@dp.message_handler(commands=[\"start\"])\nasync def ask_question(message: Message):\n    await aiostep.register_next_step(message.chat.id, handle_answer)\n    await message.reply(\"What's your name?\")\n\nasync def handle_answer(message: Message):\n    await message.reply(f\"Hello, {message.text}!\")\n```\n\n### Using States\n**Aiostep supports managing user states to handle multi-step workflows. Unlike the previous methods, managing states does not require the `Listen` middleware.**\n\n\n#### 1. Memory State Storage:\n- This is an in-memory implementation suitable for temporary state storage.\n\n**Example:**\n\n```python\nfrom aiostep import MemoryStateStorage\n\nstate_manager = MemoryStateStorage()\n\n@dp.message_handler(commands=[\"start\"])\nasync def start_process(message: Message):\n    state_manager.set_state(\n        user_id=message.from_user.id,\n        state=\"STEP_ONE\"\n    )\n    await message.reply(\"State set to STEP_ONE!\")\n\n@dp.message_handler(lambda message: state_manager.get_state(message.from_user.id).current_state == \"STEP_ONE\")\nasync def handle_step_one(message: Message):\n    await message.reply(\"You're in STEP_ONE.\")\n```\n\n**Returning to Previous State:**\n```python\n@dp.message_handler(lambda message: message.text == \"Back\")\nasync def go_back(message: Message):\n    step = state_manager.get_state(message.from_user.id)\n    if step and step.callback:\n        await step.callback(message)\n    else:\n        await message.reply(\"No previous state found.\")\n```\n> [!NOTE]\\\n> You should manually use getattr to find and call the back step handler if you use `RedisStateStorage` or `FileStateStorage`, because callbacks are saved as strings (function name)\n>```python\n>@dp.message_handler(lambda message: message.text == \"Back\")\n>async def go_back(message: Message):\n>    step = await state_manager.get_state(message.from_user.id)\n>    if step and step.callback:\n>        callback = getattr(step.callback)\n>        await callback(message)\n>    else:\n>        await message.reply(\"No previous state found.\")\n>```\n\n#### 2. Other Storage Options:\n- File-based and Redis storage implementations are also available, providing similar functionality with persistent data storage.\n- Simply replace MemoryStateStorage with FileStateStorage or RedisStateStorage when initializing the state manager.\n> [!NOTE]\\\n> Methods in `MemoryStateStorage`, `FileStateStorage` and `RedisStateStorage` are synchronous.\n> **If you want use asynchronous versions, use `aiostep.asyncio`:**\n> ```python\n> from aiostep.asyncio import AsyncMemoryStateStorage\n> from aiostep.asyncio import AsyncFileStateStorage\n> from aiostep.asyncio import AsyncRedisStateStorage\n> ```\n\n#### 3. Timeout States\n\nTo set a timeout (expiry) for the state storage, you can use the `ex` argument for both `RedisStateStorage` and `FileStateStorage`.\nBut for `MemoryStateStorage` you need to pass a TTLCache if you want set timeout.\n\nHere's how you can set it up:\n\n- **For `MemoryStateStorage`** (using `cachebox.TTLCache`):\n\n    ```python\n    from aiostep import MemoryStateStorage\n    from cachebox import TTLCache  # cachetools.TTLCache also works\n\n    # Create a TTLCache with a timeout of 200 seconds\n    storage = MemoryStateStorage(TTLCache(0, 200))  # Timeout is 200 seconds\n    ```\n\n- **For `RedisStateStorage`** (using the `ex` argument for expiry time):\n\n    ```python\n    from aiostep import RedisStateStorage\n    from aiostep import FileStateStorage\n\n    # Create RedisStateStorage with a timeout of 200 seconds\n    storage = RedisStateStorage(db=0, ex=200)  # Timeout (expiry) is 200 seconds\n    storage = FileStateStorage(\"path.txt\", ex=200)  # Same as RedisStateStorage\n    ```\nIn both cases, the state will automatically expire after the specified time, and the data will be removed from the storage.\n\n---\n\n### Using Data\n\n#### Setting Data\n\n```python\nstate_manager.set_data(\n    user_id=message.from_user.id,\n    data={\"key\": \"value\"}\n)\n```\n\n#### Getting Data\n\n```python\ndata = state_manager.get_data(user_id=message.from_user.id)\nawait message.reply(f\"Your data: {data}\")\n```\n\n---\n\n## Important Notes\n\n1. **Callbacks**:\n   - Callbacks can be any callable object, such as functions.\n   - In `FileStateStorage` and `RedisStateStorage` they are stored as strings (e.g. function name).\n\n3. **Storage Flexibility**:\n   - The memory-based implementation is ideal for development and testing.\n   - Persistent storage like Redis is recommended for production.\n\n---\n\n## Future Plans\n\n- **Better Library Compatibility**: Enhanced support for other Telegram bot libraries such as `pyTelegramBotAPI` and `python-telegram-bot`, in addition to `aiogram`.\n- **Improved Documentation**: Detailed guides and best practices.\n\n---\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.\n\n---\n\nFor more information or to contribute, visit our [GitHub repository](#).\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A Python library to handle steps in aiogram framework.",
    "version": "0.3.4",
    "project_urls": {
        "Homepage": "https://github.com/NasrollahYusefi/aiostep"
    },
    "split_keywords": [
        "aiogram",
        " steps",
        " states",
        " telegram bot",
        " asynchronous",
        " aiostep"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ce5e7b6f0cf22b41a73e7fcc572573cf33bf564568c8b7f64241ccfff724d9f6",
                "md5": "c91032fd0bdda6a0c75974d847a50273",
                "sha256": "3f2f12e092a4431fcd70e51c3118b9c65412f972d7492cd473d706009b23318d"
            },
            "downloads": -1,
            "filename": "aiostep-0.3.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c91032fd0bdda6a0c75974d847a50273",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.9",
            "size": 47330,
            "upload_time": "2025-01-26T17:29:23",
            "upload_time_iso_8601": "2025-01-26T17:29:23.652680Z",
            "url": "https://files.pythonhosted.org/packages/ce/5e/7b6f0cf22b41a73e7fcc572573cf33bf564568c8b7f64241ccfff724d9f6/aiostep-0.3.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2f7d847f5eafe02bce39a1236845ccc29d7d12ccaaaccc028892fb274c493c90",
                "md5": "a8b129b4fc57fbee317aebf2a2682d00",
                "sha256": "cfb74c8639f567dc1066783d1c02fa8969f97ee330f716e29168d60f835bdefb"
            },
            "downloads": -1,
            "filename": "aiostep-0.3.4.tar.gz",
            "has_sig": false,
            "md5_digest": "a8b129b4fc57fbee317aebf2a2682d00",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.9",
            "size": 29334,
            "upload_time": "2025-01-26T17:29:26",
            "upload_time_iso_8601": "2025-01-26T17:29:26.922166Z",
            "url": "https://files.pythonhosted.org/packages/2f/7d/847f5eafe02bce39a1236845ccc29d7d12ccaaaccc028892fb274c493c90/aiostep-0.3.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-01-26 17:29:26",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "NasrollahYusefi",
    "github_project": "aiostep",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "aiostep"
}
        
Elapsed time: 1.35505s