mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Some checks failed
Tests / tests (macos-latest, 3.10) (push) Has been cancelled
Tests / tests (macos-latest, 3.11) (push) Has been cancelled
Tests / tests (macos-latest, 3.12) (push) Has been cancelled
Tests / tests (macos-latest, 3.13) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.10) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.13) (push) Has been cancelled
Tests / tests (windows-latest, 3.10) (push) Has been cancelled
Tests / tests (windows-latest, 3.11) (push) Has been cancelled
Tests / tests (windows-latest, 3.12) (push) Has been cancelled
Tests / tests (windows-latest, 3.13) (push) Has been cancelled
Tests / pypy-tests (macos-latest, pypy3.10) (push) Has been cancelled
Tests / pypy-tests (macos-latest, pypy3.11) (push) Has been cancelled
Tests / pypy-tests (ubuntu-latest, pypy3.10) (push) Has been cancelled
Tests / pypy-tests (ubuntu-latest, pypy3.11) (push) Has been cancelled
* Drop py3.9 and pypy3.9 Add pypy3.11 (testing) into `tests.yml` Remove py3.9 from matrix in `tests.yml` Refactor not auto-gen code to be compatible with py3.10+, droping ugly 3.9 annotation. Replace some `from typing` imports to `from collections.abc`, due to deprecation Add `from __future__ import annotations` and `if TYPE_CHECKING:` where possible Add some `noqa` to calm down Ruff in some places, if Ruff will be used as default linting+formatting tool in future Replace some relative imports to absolute Sort `__all__` tuples in `__init__.py` and some other `.py` files Sort `__slots__` tuples in classes Split raises into `msg` and `raise` (`EM101`, `EM102`) to not duplicate error message in the traceback Add `Self` from `typing_extenstion` where possible Resolve typing problem in `aiogram/filters/command.py:18` Concatenate nested `if` statements Convert `HandlerContainer` into a dataclass in `aiogram/fsm/scene.py` Bump tests docker-compose.yml `redis:6-alpine` -> `redis:8-alpine` Bump tests docker-compose.yml `mongo:7.0.6` -> `mongo:8.0.14` Bump pre-commit-config `black==24.4.2` -> `black==25.9.0` Bump pre-commit-config `ruff==0.5.1` -> `ruff==0.13.3` Update Makefile lint for ruff to show fixes Add `make outdated` into Makefile Use `pathlib` instead of `os.path` Bump `redis[hiredis]>=5.0.1,<5.3.0` -> `redis[hiredis]>=6.2.0,<7` Bump `cryptography>=43.0.0` -> `cryptography>=46.0.0` due to security reasons Bump `pytz~=2023.3` -> `pytz~=2025.2` Bump `pycryptodomex~=3.19.0` -> `pycryptodomex~=3.23.0` due to security reasons Bump linting and formatting tools * Add `1726.removal.rst` * Update aiogram/utils/dataclass.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update aiogram/filters/callback_data.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update 1726.removal.rst * Remove `outdated` from Makefile * Add `__slots__` to `HandlerContainer` * Remove unused imports * Add `@dataclass` with `slots=True` to `HandlerContainer` --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
95 lines
2.8 KiB
Python
95 lines
2.8 KiB
Python
from asyncio import Lock
|
|
from collections import defaultdict
|
|
from collections.abc import AsyncGenerator, Hashable, Mapping
|
|
from contextlib import asynccontextmanager
|
|
from copy import copy
|
|
from dataclasses import dataclass, field
|
|
from typing import Any, overload
|
|
|
|
from aiogram.exceptions import DataNotDictLikeError
|
|
from aiogram.fsm.state import State
|
|
from aiogram.fsm.storage.base import (
|
|
BaseEventIsolation,
|
|
BaseStorage,
|
|
StateType,
|
|
StorageKey,
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class MemoryStorageRecord:
|
|
data: dict[str, Any] = field(default_factory=dict)
|
|
state: str | None = None
|
|
|
|
|
|
class MemoryStorage(BaseStorage):
|
|
"""
|
|
Default FSM storage, stores all data in :class:`dict` and loss everything on shutdown
|
|
|
|
.. warning::
|
|
|
|
Is not recommended using in production in due to you will lose all data
|
|
when your bot restarts
|
|
"""
|
|
|
|
def __init__(self) -> None:
|
|
self.storage: defaultdict[StorageKey, MemoryStorageRecord] = defaultdict(
|
|
MemoryStorageRecord,
|
|
)
|
|
|
|
async def close(self) -> None:
|
|
pass
|
|
|
|
async def set_state(self, key: StorageKey, state: StateType = None) -> None:
|
|
self.storage[key].state = state.state if isinstance(state, State) else state
|
|
|
|
async def get_state(self, key: StorageKey) -> str | None:
|
|
return self.storage[key].state
|
|
|
|
async def set_data(self, key: StorageKey, data: Mapping[str, Any]) -> None:
|
|
if not isinstance(data, dict):
|
|
msg = f"Data must be a dict or dict-like object, got {type(data).__name__}"
|
|
raise DataNotDictLikeError(msg)
|
|
self.storage[key].data = data.copy()
|
|
|
|
async def get_data(self, key: StorageKey) -> dict[str, Any]:
|
|
return self.storage[key].data.copy()
|
|
|
|
@overload
|
|
async def get_value(self, storage_key: StorageKey, dict_key: str) -> Any | None: ...
|
|
|
|
@overload
|
|
async def get_value(self, storage_key: StorageKey, dict_key: str, default: Any) -> Any: ...
|
|
|
|
async def get_value(
|
|
self,
|
|
storage_key: StorageKey,
|
|
dict_key: str,
|
|
default: Any | None = None,
|
|
) -> Any | None:
|
|
data = self.storage[storage_key].data
|
|
return copy(data.get(dict_key, default))
|
|
|
|
|
|
class DisabledEventIsolation(BaseEventIsolation):
|
|
@asynccontextmanager
|
|
async def lock(self, key: StorageKey) -> AsyncGenerator[None, None]:
|
|
yield
|
|
|
|
async def close(self) -> None:
|
|
pass
|
|
|
|
|
|
class SimpleEventIsolation(BaseEventIsolation):
|
|
def __init__(self) -> None:
|
|
# TODO: Unused locks cleaner is needed
|
|
self._locks: defaultdict[Hashable, Lock] = defaultdict(Lock)
|
|
|
|
@asynccontextmanager
|
|
async def lock(self, key: StorageKey) -> AsyncGenerator[None, None]:
|
|
lock = self._locks[key]
|
|
async with lock:
|
|
yield
|
|
|
|
async def close(self) -> None:
|
|
self._locks.clear()
|