Skip to main content

A flexible state machine framework for Python

Reason this release was yanked:

Major upgrades made in the architecture resulting in breaking changes.

Project description

State Machine Framework

A flexible state machine framework for Python with clean abstractions, ORM integration support, and type-safe workflow management.

Features

  • ๐ŸŽฏ Clean State Definitions: Minimal boilerplate with decorator-based validators and hooks
  • ๐Ÿ”„ Integration Agnostic: Works ORM via adapter pattern
  • โœ… Type Safety: Pydantic schema validation and type-checked workflow contexts
  • ๐ŸŽจ External Registration: Register validators and hooks in separate modules for clean code organization
  • ๐Ÿ“‹ Workflow Context: Type-safe context management with automatic validation

Installation

pip install state-machine-framework

Quick Start

1. Define Your Models

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Order(Base):
    __tablename__ = 'orders'
    
    id = Column(Integer, primary_key=True)
    order_id = Column(String(100), unique=True)
    status = Column(String(50))

2. Define States

from state_machine_framework import State

class OrderPending(State):
    is_start_state = True
    
    class Meta:
        order = 1
        Order_status = 'pending'

class OrderProcessing(State):
    class Meta:
        order = 2
        Order_status = 'processing'

class OrderCompleted(State):
    is_terminal_state = True
    
    class Meta:
        order = 3
        Order_status = 'completed'

3. Define State Machine

from state_machine_framework import StateMachine

class OrderStateMachine(StateMachine):
    pass

OrderStateMachine.register(
    Order,
    state_field='status',
    identifier_field='order_id'
)

4. Add Validators (External Registration)

from state_machine_framework import validator

@validator(OrderPending, order=1)
def validate_order_amount(state, data, context):
    if data.get('amount', 0) <= 0:
        raise ValueError("Invalid amount")
    return {'validated': True}

5. Add Hooks (External Registration)

from state_machine_framework import hook

@hook(OrderProcessing, order=1)
def send_confirmation_email(state, data, context):
    order = data['instances']['Order']
    send_email(order.customer_email)
    return {'email_sent': True}

6. Define Pydantic Schemas

from pydantic import BaseModel, Field

class OrderData(BaseModel):
    amount: float = Field(..., gt=0)
    customer_email: str

7. Define Workflow Context

from state_machine_framework import WorkflowContext

class OrderWorkflowContext(WorkflowContext):
    def define_requirements(self):
        self.require_value('customer_id', str)
        self.require_model('order', Order, created_in_state=OrderPending)
        self.require_dict('order_data', OrderData)

8. Execute Workflow

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine('sqlite:///orders.db')
Session = sessionmaker(bind=engine)
session = Session()

with OrderWorkflowContext(
    OrderStateMachine,
    customer_id='CUST123',
    order_data={'amount': 99.99, 'customer_email': 'user@example.com'},
    _session=session
) as workflow:
    
    workflow.transition_to(OrderPending)
    workflow.transition_to(OrderProcessing)
    workflow.transition_to(OrderCompleted)
    
    print(workflow.get_history_summary())

Package Structure

state_machine_framework/
โ”œโ”€โ”€ __init__.py              # Main package exports
โ”œโ”€โ”€ core/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ state.py             # State base class and metaclass
โ”‚   โ”œโ”€โ”€ state_machine.py     # StateMachine base class
โ”‚   โ””โ”€โ”€ exceptions.py        # Custom exceptions
โ”œโ”€โ”€ decorators/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ hooks.py             # Decorators for validators, hooks, transitions
โ”œโ”€โ”€ orm/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ base.py              # Abstract ORM adapter
โ”‚   โ””โ”€โ”€ sqlalchemy_adapter.py # SQLAlchemy implementation
โ””โ”€โ”€ workflow/
    โ”œโ”€โ”€ __init__.py
    โ”œโ”€โ”€ context.py           # WorkflowContext implementation
    โ””โ”€โ”€ requirements.py      # Context requirement classes

Key Concepts

States

States represent points in your workflow. Define them by subclassing State:

class MyState(State):
    is_start_state = True  # Optional: mark as initial state
    is_terminal_state = False  # Optional: mark as final state
    
    class Meta:
        order = 1  # Execution order
        ModelName_status = 'state_value'  # State value for model

Validators

Validators run before state transitions and perform validation logic:

@validator(MyState, order=1)
def validate_something(state, data, context):
    # Validation logic here
    if not valid:
        raise ValueError("Validation failed")
    return {'result': 'validated'}

Hooks

Hooks run after state transitions and perform side effects:

@hook(MyState, order=1)
def do_something(state, data, context):
    # Side effects here (logging, notifications, etc.)
    instances = data['instances']  # Access model instances
    return {'action': 'completed'}

Workflow Context

Workflow contexts provide type-safe, validated context management:

class MyWorkflowContext(WorkflowContext):
    def define_requirements(self):
        # Require a simple value
        self.require_value('user_id', str, required=True)
        
        # Require a model instance (may be created during workflow)
        self.require_model('order', Order, created_in_state=OrderPending)
        
        # Require a dict validated by Pydantic schema
        self.require_dict('order_data', OrderDataSchema, required=True)

Examples

See the examples/ directory for a complete vending machine implementation demonstrating:

  • SQLAlchemy ORM integration
  • Workflow context with validation
  • External validator and hook registration
  • Type-safe context management
  • Pydantic schema validation
  • Complete transaction workflow

To run the example:

cd examples/vending_machine
python main.py

Dynamic ORM Adapters

Implement the ORMAdapter interface for your ORM:

from state_machine_framework import ORMAdapter, ORMAdapterFactory

class MyORMAdapter(ORMAdapter):
    def create(self, model_cls, **data):
        # Your implementation
        pass
    
    # ... implement all abstract methods

# Register it
ORMAdapterFactory.register_adapter('myorm', MyORMAdapter)

# Use it
sm = MyStateMachine(data, using_orm='myorm')

Requirements

  • Python 3.8+
  • pydantic >= 1.8.0

License

MIT License - see LICENSE file for details

Contributing

Contributions are welcome! Please feel free to reach out...

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

state_machine_framework-1.0.0.tar.gz (5.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

state_machine_framework-1.0.0-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

Details for the file state_machine_framework-1.0.0.tar.gz.

File metadata

  • Download URL: state_machine_framework-1.0.0.tar.gz
  • Upload date:
  • Size: 5.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.9

File hashes

Hashes for state_machine_framework-1.0.0.tar.gz
Algorithm Hash digest
SHA256 021713e330ea6bb837e12d7a34bab03e3f82090b45aa47abc69744a2131b1997
MD5 ca0001b110719d83154e8affb899ae71
BLAKE2b-256 29775918fd7fc211b06dda212568c100a6a3b92f5b44a5480f849a6c000ee737

See more details on using hashes here.

File details

Details for the file state_machine_framework-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for state_machine_framework-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 73acbeb1c465b62ca84688f6267265801beda833436b3f87e41eafb6b8a3cdcf
MD5 def5018b1a826ff2db1375c3846dbc63
BLAKE2b-256 391cd8a204b748a9375c628f21bc90560c1b654d709959da30ba0ad5196ff19f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page