Skip to content

shenning00/async_sdl_python

PySDL - Python Asynchronous SDL Library

Python Version License: MIT CI codecov

A lightweight, asynchronous Python library implementing the Specification and Description Language (SDL) actor model pattern for building concurrent, event-driven applications.

Overview

PySDL provides a clean, type-safe framework for building applications based on the actor model and finite state machines. It leverages Python's asyncio for efficient concurrent execution while maintaining clean separation of concerns through message passing.

Key Features:

  • Actor Model Implementation: Processes communicate exclusively through asynchronous signals
  • Finite State Machines: Define complex behavior through clean state transitions
  • Star Wildcard Matching: Handle signals from any state or any signal in a state
  • Type-Safe Design: Comprehensive type hints for better IDE support and type checking
  • Async/Await Native: Built on asyncio for high-performance concurrent execution
  • Timer Support: Multiple concurrent timers per process with millisecond precision
  • Process Hierarchies: Parent-child process relationships with lifecycle management
  • Singleton Processes: Built-in support for singleton service patterns
  • Configurable Logging: Fine-grained control over logging with minimal performance overhead

Quick Start

Installation

Using pip (when published to PyPI):

pip install pysdl

From source:

git clone https://github.com/shenning00/async_sdl_python.git
cd async_sdl_python
# Upgrade pip first to avoid installation issues
python -m pip install --upgrade pip
# Install in editable mode with dev dependencies
pip install -e ".[dev]"

Note: Upgrading pip is recommended to ensure editable installs work correctly with pyproject.toml-based projects.

Using PYTHONPATH (for development):

export PYTHONPATH=/path/to/async_sdl_python:$PYTHONPATH

Hello World Example

Here's a simple ping-pong example demonstrating the core concepts:

import asyncio
from pysdl import (
    SdlProcess, SdlSignal, SdlState, SdlSystem, SdlStartSignal,
    start
)


class PingSignal(SdlSignal):
    """A ping signal."""
    def dumpdata(self):
        return "Ping!"


class PingPongProcess(SdlProcess):
    """Process that responds to ping signals."""

    state_wait_ping = SdlState("wait_ping")

    def __init__(self, parent_pid, peer_pid=None, system=None):
        super().__init__(parent_pid, system=system)
        self.peer_pid = peer_pid

    async def start_StartTransition(self, _):
        """Initial state: send ping to peer if available."""
        if self.peer_pid:
            await self.output(PingSignal.create(), self.peer_pid)
        await self.next_state(self.state_wait_ping)

    async def wait_ping_PingSignal(self, signal):
        """Respond to ping by sending it back."""
        await self.output(signal, signal.src())

    def _init_state_machine(self):
        """Define the state machine."""
        self._event(start, SdlStartSignal, self.start_StartTransition)
        self._event(self.state_wait_ping, PingSignal, self.wait_ping_PingSignal)
        self._done()


async def main():
    """Create processes and run the system."""
    # Create a system instance
    system = SdlSystem()

    # Create processes with the system instance
    p1 = await PingPongProcess.create(None, system=system)
    p2 = await PingPongProcess.create(None, p1.pid(), system=system)

    # Run the system
    await system.run()


if __name__ == "__main__":
    asyncio.run(main())

Core Concepts

Processes (Actors)

Processes are independent actors that:

  • Maintain their own internal state
  • Communicate only through signals (messages)
  • Execute state transitions in response to signals
  • Can create child processes
  • Can start and stop timers

Signals (Messages)

Signals are typed messages that:

  • Are routed between processes by PID
  • Carry optional data payloads
  • Trigger state transitions when received
  • Are queued and processed asynchronously

States & State Machines

State machines define process behavior:

  • Each process has exactly one current state
  • States define which signals trigger which handlers
  • Handlers can send signals and transition to new states
  • State transitions are logged automatically

Timers

Timers enable time-based behavior:

  • Multiple concurrent timers per process
  • Millisecond precision
  • Automatic delivery as signals when expired
  • Can be started, stopped, and restarted

Documentation

Project Structure

async_sdl_python/
├── pysdl/                  # Core library package
│   ├── __init__.py         # Public API exports
│   ├── system.py           # Event loop and system management
│   ├── process.py          # Process base classes
│   ├── signal.py           # Signal base class
│   ├── state.py            # State representation
│   ├── state_machine.py    # FSM implementation
│   ├── timer.py            # Timer implementation
│   ├── logger.py           # Event logging
│   ├── children_manager.py # Child process management
│   ├── id_generator.py     # Unique ID generation
│   ├── registry.py         # Name-based process registry
│   └── system_signals.py   # Built-in system signals
├── tests/                  # Test suite
├── docs/                   # Documentation
├── examples/               # Example applications
│   └── main.py             # Ping-pong example
└── README.md               # This file

Requirements

  • Python: 3.9 or higher (uses type hints and async features)
  • Dependencies: None (uses only Python standard library)
  • Development Dependencies:
    • pytest >= 8.0
    • pytest-asyncio >= 0.23
    • pytest-cov >= 4.1
    • mypy >= 1.13 (for type checking)
    • ruff >= 0.8 (for linting)

Testing

Run the test suite:

# Run all tests
pytest

# Run with coverage
pytest --cov=pysdl --cov-report=html

# Run type checking
mypy pysdl/

# Run linting
ruff check pysdl/

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for new functionality
  4. Ensure all tests pass and coverage remains high
  5. Run type checking and linting
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Merge Request

Development Guidelines

  • Type Safety: All code must have comprehensive type hints
  • Testing: Maintain >90% test coverage
  • Documentation: Update docs for API changes
  • Code Style: Follow PEP 8, use ruff formatter
  • Async: Use async/await properly, avoid blocking calls
  • Logging: Use SdlLogger for framework events

License

This project is licensed under the MIT License - see the LICENSE file for details.

Authors

  • Scott Henning - Initial work

Acknowledgments

  • Inspired by the ITU-T Z.100 Specification and Description Language (SDL)
  • Built on Python's powerful asyncio framework
  • Designed for clarity, type safety, and performance

Support

Roadmap

Future enhancements under consideration:

  • Instance-based system design (multiple independent systems) - Completed in v1.0.0
  • Enhanced debugging and introspection tools
  • State machine visualization
  • Performance benchmarking suite
  • Additional example applications
  • Integration with popular async frameworks

Version History

  • 1.0.0 (2024-10-26) - Instance-based system [BREAKING CHANGES]

    • Refactored SdlSystem from static class to instance-based
    • Added system parameter to SdlProcess creation and initialization
    • Processes now reference their system instance via self._system
    • Enables multiple independent systems in the same process
    • Eliminates global state for better testability
    • All tests updated (242 tests, 83% coverage)
    • All examples updated to use instance-based API
  • 0.0.1 - Initial release

    • Core actor model implementation
    • Async signal routing
    • Finite state machines
    • Timer support
    • Process hierarchies
    • Type-safe API

About

Python State Machine Library

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages