FSM¶
StateGroup¶
StateGroup
¶
A group of related states.
StateGroup provides a way to organize states logically and access them as class attributes.
Examples:
class OrderStates(StateGroup): waiting_name = State() waiting_phone = State() confirm = State()
Access states¶
OrderStates.waiting_name #
Get all states¶
OrderStates.all_states() # [State, State, State]
Check if state is in group¶
OrderStates.waiting_name in OrderStates.all_states() # True
all_states
classmethod
¶
Get all states in this group.
Returns:
| Type | Description |
|---|---|
list[State]
|
List of all State objects in this group. |
get_state
classmethod
¶
Get a state by its short name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The short name of the state (without group prefix). |
required |
Returns:
| Type | Description |
|---|---|
State | None
|
The State object or None if not found. |
Source code in vkflow\app\fsm\state.py
__contains__
classmethod
¶
Check if a state belongs to this group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item
|
State | str
|
State object or state name string. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the state is in this group. |
Source code in vkflow\app\fsm\state.py
State¶
State
dataclass
¶
Represents a state in FSM.
Can be used as: - Standalone state: state = State("waiting_name") - Part of StateGroup: waiting_name = State() inside class
Examples:
Standalone¶
my_state = State("waiting_input")
In StateGroup¶
class OrderStates(StateGroup): waiting_name = State() waiting_phone = State()
Access¶
OrderStates.waiting_name.name # "OrderStates:waiting_name"
Initialize a State.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | None
|
Optional explicit name. If not provided, will be set automatically when used in StateGroup. |
None
|
Source code in vkflow\app\fsm\state.py
name
property
¶
Full state name: "GroupName:state_name" or just "state_name".
Returns:
| Type | Description |
|---|---|
str
|
The full qualified name of the state. |
state
property
¶
Short state name (without group).
Returns:
| Type | Description |
|---|---|
str
|
The state name without group prefix. |
group
property
¶
The StateGroup this state belongs to.
Returns:
| Type | Description |
|---|---|
type | None
|
The StateGroup class or None if standalone. |
FSMRouter¶
FSMRouter
¶
Router for FSM state handlers.
FSMRouter provides a standalone way to register and dispatch FSM state handlers, independent of the Cog system.
Features: - Register handlers with @router.state() decorator - Before/after state hooks - Automatic argument injection - Process messages through registered handlers
Examples:
from vkflow.app.fsm import FSMRouter, MemoryStorage, StateGroup, State
class OrderStates(StateGroup): waiting_name = State() waiting_phone = State()
storage = MemoryStorage() router = FSMRouter(storage)
@router.state(OrderStates.waiting_name) async def handle_name(ctx, msg): await ctx.update_data(name=msg.msg.text) await ctx.set_state(OrderStates.waiting_phone) await msg.answer("Enter phone:")
@router.state(OrderStates.waiting_phone) async def handle_phone(ctx, msg): data = await ctx.finish() await msg.answer(f"Order: {data['name']}, {msg.msg.text}")
Register in app¶
app.include_fsm_router(router)
Initialize FSMRouter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
storage
|
BaseStorage
|
FSM storage backend |
required |
strategy
|
KeyStrategy | str
|
Key generation strategy |
USER_CHAT
|
name
|
str | None
|
Optional router name for debugging |
None
|
Source code in vkflow\app\fsm\router.py
state
¶
Decorator to register a state handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
State | str
|
State object or state name string |
required |
Returns:
| Type | Description |
|---|---|
Callable[[Handler], Handler]
|
Decorator function |
Examples:
@router.state(OrderStates.waiting_name) async def handle_name(ctx: fsm.Context, msg: NewMessage): await ctx.update_data(name=msg.msg.text) await ctx.set_state(OrderStates.waiting_phone)
Source code in vkflow\app\fsm\router.py
before_state
¶
Decorator for before-state hook.
Hook is called before any state handler. If it returns False, the state handler will be skipped.
Examples:
@router.before_state() async def log_before(ctx, msg): logger.info(f"Processing state for {msg.msg.from_id}")
Source code in vkflow\app\fsm\router.py
after_state
¶
Decorator for after-state hook.
Hook is called after state handler completes (success or failure).
Examples:
@router.after_state() async def log_after(ctx, msg): logger.info(f"Finished processing for {msg.msg.from_id}")
Source code in vkflow\app\fsm\router.py
get_handler
¶
Get handler for a state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
str
|
State name |
required |
Returns:
| Type | Description |
|---|---|
StateHandler | None
|
StateHandler or None if not found |
get_states
¶
Get all registered state names.
Returns:
| Type | Description |
|---|---|
list[str]
|
List of state name strings |
process
async
¶
Process a message through FSM handlers.
Checks if user is in a registered state and invokes the corresponding handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
NewMessage | CallbackButtonPressed
|
Message to process |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if a handler was invoked, False otherwise |
Source code in vkflow\app\fsm\router.py
FSMContext¶
StateFilter¶
StateFilter
dataclass
¶
Bases: BaseFilter
Filter for checking FSM state before command execution.
StateFilter integrates FSM with the existing command system. It checks if user is in a specific state before allowing the command to execute.
Examples:
Filter for specific state¶
@app.command("next", filter=StateFilter(OrderStates.waiting_name, storage)) async def handle_name(ctx: NewMessage): ...
Filter for any state in group¶
@app.command("cancel", filter=StateFilter.any(OrderStates, storage)) async def cancel(ctx: NewMessage): ...
Filter for no active state¶
@app.command("start", filter=StateFilter.none(storage)) async def start(ctx: NewMessage): ...
Combine with other filters¶
combined = StateFilter(MyStates.waiting, storage) & SomeOtherFilter()
Create a StateFilter for specific state(s).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
State | str | list[State | str]
|
Single state or list of states to match |
required |
storage
|
BaseStorage
|
FSM storage backend |
required |
strategy
|
KeyStrategy | str
|
Key generation strategy |
USER_CHAT
|
Source code in vkflow\app\fsm\filter.py
any
classmethod
¶
Create filter that matches ANY state in a StateGroup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
group
|
type
|
StateGroup class |
required |
storage
|
BaseStorage
|
FSM storage backend |
required |
strategy
|
KeyStrategy | str
|
Key generation strategy |
USER_CHAT
|
Returns:
| Type | Description |
|---|---|
StateFilter
|
StateFilter that passes if user is in any state of the group. |
Examples:
@app.command("cancel", filter=StateFilter.any(OrderStates, storage)) async def cancel(ctx: NewMessage): # Works when user is in ANY OrderStates state ...
Source code in vkflow\app\fsm\filter.py
none
classmethod
¶
Create filter that matches when NO state is active.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
storage
|
BaseStorage
|
FSM storage backend |
required |
strategy
|
KeyStrategy | str
|
Key generation strategy |
USER_CHAT
|
Returns:
| Type | Description |
|---|---|
StateFilter
|
StateFilter that passes only if user has no active state. |
Examples:
@app.command("start", filter=StateFilter.none(storage)) async def start(ctx: NewMessage): # Only works when user is NOT in any state ...
Source code in vkflow\app\fsm\filter.py
make_decision
async
¶
Check if the current state matches filter criteria.
Raises:
| Type | Description |
|---|---|
StopCurrentHandlingError
|
If state doesn't match |
Source code in vkflow\app\fsm\filter.py
MemoryStorage¶
MemoryStorage
¶
Bases: BaseStorage
In-memory FSM storage implementation.
Stores FSM state and data in Python dictionaries. Data is lost when the bot restarts.
Features: - Thread-safe via asyncio.Lock - Optional TTL for automatic state expiration - Zero dependencies
Best for: - Development and testing - Small bots where persistence isn't critical - Stateless deployments
Examples:
Basic usage¶
storage = MemoryStorage()
With TTL (states expire after 1 hour)¶
storage = MemoryStorage(ttl=3600)
Use with FSMRouter¶
router = FSMRouter(storage)
Initialize MemoryStorage.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ttl
|
float | None
|
Optional time-to-live in seconds for states. If set, states older than TTL will be automatically cleared on next access. None means no expiration. |
None
|