snakia


Namesnakia JSON
Version 0.4.0 PyPI version JSON
download
home_pageNone
SummaryModern python framework
upload_time2025-10-26 16:29:09
maintainerNone
docs_urlNone
authorrus07tam
requires_python>=3.12
licenseNone
keywords python3 event system ecs reactive programming
VCS
bugtrack_url
requirements annotated-types networkx pydantic pydantic-core typing-extensions typing-inspection
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 🐍 Snakia Framework

**Snakia** is a modern Python framework for creating applications with Entity-Component-System (ECS) architecture, event system, and reactive programming. Built with performance (maybe) and modularity in mind, Snakia provides a clean API for developing complex applications ranging from games to terminal user interfaces.

## 📋 Table of Contents

- [🎯 Roadmap & TODO](#-roadmap--todo)
- [🚀 Installation](#-installation)
- [🚀 Quick Start](#-quick-start)
- [🏗️ Architecture](#️-architecture)
- [⚙️ Core](#️-core)
- [🎯 ECS System](#-ecs-system)
- [📡 Event System (ES)](#-event-system-es)
- [🔌 Plugin System](#-plugin-system)
- [🎨 TUI System](#-tui-system)
- [⚡ Reactive Programming (RX)](#-reactive-programming-rx)
- [🛠️ Utilities](#️-utilities)
- [🎭 Decorators](#-decorators)
- [🏷️ Properties](#-properties)
- [🌐 Platform Abstraction](#-platform-abstraction)
- [📦 Examples](#-examples)
- [🤝 Contributing](#-contributing)
- [🆘 Support](#-support)
- [📄 License](#-license)

### ✨ Key Features

- 🏗️ **ECS Architecture** - Flexible entity-component-system for scalable game/app logic
- 📡 **Event System** - Asynchronous event handling with filters and priorities
- 🔌 **Plugin System** - Modular plugin architecture for extensibility
- 🎨 **TUI Framework** - Rich terminal user interface with reactive widgets
- ⚡ **Reactive Programming** - Observable data streams and reactive bindings
- 🛠️ **Rich Utilities** - Decorators, properties, platform abstraction, and more
- 🎯 **Type Safety** - Full type hints and Pydantic integration

> ⚠️ **Experimental Framework**  
> This framework is currently in **beta/experimental stage**. Not all features are fully implemented, there might be bugs, and the API is subject to change. Use at your own risk! 🚧

## 🚀 Installation

### Prerequisites

- **Python** >= 3.12
- **pip** or **uv** (recommended) package manager

### Install from PyPi (recommended)

```bash
pip install snakia
```

### Install from Source

```bash
# Clone the repository
git clone https://github.com/RuJect/Snakia.git
cd Snakia

# Install with pip
pip install -e .

# Or with uv (recommended)
uv sync
```

## 🎯 Roadmap & TODO

Here's what we're working on to make Snakia even better:

- [ ] Plugin Isolation: restrict plugin access to only events and components statically defined in manifest
- [ ] Async & Multithreading: implement proper async/await support and multithreading capabilities  
- [ ] Platform Support: expand platform abstraction to support more operating systems
- [ ] Random Implementations: add various random generations implementations
- [ ] TUI Widgets: create more ready-to-use TUI widgets and components
- [ ] Code Documentation: add comprehensive docstrings and inline comments
- [ ] Documentation: create detailed API documentation and tutorials

## 🚀 Quick Start

```python
from snakia.core.engine import Engine
from snakia.core.loader import Meta, Plugin, PluginProcessor
from snakia.core.ecs import Component
from snakia.types import Version

# Creating a component
class HealthComponent(Component):
    value: int = 100
    max_value: int = 100

# Creating a processor
class HealthProcessor(PluginProcessor):
    def process(self, system):
        for entity, (health,) in system.get_components(HealthComponent):
            if health.value <= 0:
                print(f"Entity {entity} died!")

# Creating a plugin
class HealthPlugin(Plugin, meta=Meta(
    name="health",
    version=Version.from_args(1, 0, 0),
    processors=(HealthProcessor,)
)):
    def on_load(self): pass
    def on_unload(self): pass

# Starting the engine
engine = Engine()
engine.loader.register(HealthPlugin)
engine.loader.load_all()
engine.start()
```

## 🏗️ Architecture

Snakia is built on a modular architecture with clear separation of concerns:

```plaintext
Snakia/
├── core/           # Framework core
│   ├── engine.py   # Main engine
│   ├── ecs/        # Entity-Component-System
│   ├── es/         # Event System
│   ├── loader/     # Plugin loading system
│   ├── rx/         # Reactive programming
│   └── tui/        # Terminal User Interface
├── decorators/    # Decorators
├── property/      # Property system
├── platform/      # Platform abstraction
├── utils/         # Utilities
├── random/        # Random number generation
├── field/         # Typed fields
└── types/         # Special types
```

## ⚙️ Core

### Engine

The central component of the framework that coordinates all systems:

```python
from snakia.core.engine import Engine

engine = Engine()
# Systems:
# - engine.system    - ECS system
# - engine.dispatcher - Event system  
# - engine.loader    - Plugin loader

engine.start()  # Start all systems
engine.stop()   # Stop all systems
engine.update() # Update systems
```

## 🎯 ECS System

Entity-Component-System architecture for creating flexible and performant applications.

### Component

Base class for all components:

```python
from snakia.core.ecs import Component
from pydantic import Field

class PositionComponent(Component):
    x: float = Field(default=0.0)
    y: float = Field(default=0.0)

class VelocityComponent(Component):
    vx: float = Field(default=0.0)
    vy: float = Field(default=0.0)
```

### Processor

Processors handle components in the system:

```python
from snakia.core.ecs import Processor, System

class MovementProcessor(Processor):
    def process(self, system: System) -> None:
        # Get all entities with Position and Velocity
        for entity, (pos, vel) in system.get_components(
            PositionComponent, VelocityComponent
        ):
            pos.x += vel.vx
            pos.y += vel.vy
```

### System

Entity and component management:

```python
# Creating an entity with components
entity = system.create_entity(
    PositionComponent(x=10, y=20),
    VelocityComponent(vx=1, vy=0)
)

# Adding a component to an existing entity
system.add_component(entity, HealthComponent(value=100))

# Getting entity components
pos, vel = system.get_components_of_entity(
    entity, PositionComponent, VelocityComponent
)

# Checking for components
if system.has_components(entity, PositionComponent, VelocityComponent):
    print("Entity has position and velocity")

# Removing a component
system.remove_component(entity, VelocityComponent)

# Deleting an entity
system.delete_entity(entity)
```

## 📡 Event System (ES)

Asynchronous event system with filter and priority support.

### Event

Base class for events:

```python
from snakia.core.es import Event
from pydantic import Field

class PlayerDiedEvent(Event):
    player_id: int = Field()
    cause: str = Field(default="unknown")
    ttl: int = Field(default=10)  # Event lifetime
```

### Handler

Event handlers:

```python
from snakia.core.es import Handler, Action

def on_player_died(event: PlayerDiedEvent) -> Action | None:
    print(f"Player {event.player_id} died from {event.cause}")
    return Action.move(1)  # Move to next handler
```

### Filter

Event filters:

```python
from snakia.core.es import Filter

def only_important_deaths(event: PlayerDiedEvent) -> bool:
    return event.cause in ["boss", "pvp"]

# Using a filter
@dispatcher.on(PlayerDiedEvent, filter=only_important_deaths)
def handle_important_death(event: PlayerDiedEvent):
    print("Important death occurred!")
```

### Dispatcher

Central event dispatcher:

```python
from snakia.core.es import Dispatcher, Subscriber

dispatcher = Dispatcher()

# Subscribing to an event
dispatcher.subscribe(PlayerDiedEvent, Subscriber(
    handler=on_player_died,
    filter=only_important_deaths,
    priority=10
))

# Decorator for subscription
@dispatcher.on(PlayerDiedEvent, priority=5)
def handle_death(event: PlayerDiedEvent):
    print("Death handled!")

# Publishing an event
dispatcher.publish(PlayerDiedEvent(player_id=123, cause="boss"))
```

## 🔌 Plugin System

Modular system for loading and managing plugins.

### Plugin

Base class for plugins:

```python
from snakia.core.loader import Meta, Plugin, PluginProcessor
from snakia.types import Version

class MyProcessor(PluginProcessor):
    def process(self, system):
        # Processor logic
        pass

class MyPlugin(Plugin, meta=Meta(
    name="my_plugin",
    author="developer",
    version=Version.from_args(1, 0, 0),
    processors=(MyProcessor,),
    subscribers=()
)):
    def on_load(self):
        print("Plugin loaded!")
    
    def on_unload(self):
        print("Plugin unloaded!")
```

### Meta

Plugin metadata:

```python
from snakia.core.loader import Meta
from snakia.core.es import Subscriber

meta = Meta(
    name="plugin_name",
    author="author_name", 
    version=Version.from_args(1, 0, 0),
    processors=(Processor1, Processor2),
    subscribers=(
        (EventType, Subscriber(handler, filter, priority)),
    )
)
```

### Loader

Plugin loader:

```python
from snakia.core.loader import Loader

loader = Loader(engine)

# Registering a plugin
loader.register(MyPlugin)

# Loading all plugins
loader.load_all()

# Unloading all plugins
loader.unload_all()
```

## 🎨 TUI System

System for creating text-based user interfaces.

### Widget

Base class for widgets:

```python
from snakia.core.tui import Widget, Canvas, CanvasChar
from snakia.core.rx import Bindable

class MyWidget(Widget):
    def __init__(self):
        super().__init__()
        self.text = self.state("Hello World")
        self.color = self.state(CanvasChar(fg_color="red"))
    
    def on_render(self) -> Canvas:
        canvas = Canvas(20, 5)
        canvas.draw_text(0, 0, self.text.value, self.color.value)
        return canvas
```

### Canvas

Drawing canvas:

```python
from snakia.core.tui import Canvas, CanvasChar

canvas = Canvas(80, 24)

# Drawing text
canvas.draw_text(10, 5, "Hello", CanvasChar(fg_color="blue"))

# Drawing rectangle
canvas.draw_rect(0, 0, 20, 10, CanvasChar("█", fg_color="green"))

# Filling area
canvas.draw_filled_rect(5, 5, 10, 5, CanvasChar(" ", bg_color="red"))

# Lines
canvas.draw_line_h(0, 0, 20, CanvasChar("-"))
canvas.draw_line_v(0, 0, 10, CanvasChar("|"))
```

### CanvasChar

Character with attributes:

```python
from snakia.core.tui import CanvasChar

char = CanvasChar(
    char="A",
    fg_color="red",      # Text color
    bg_color="blue",     # Background color
    bold=True,           # Bold
    italic=False,        # Italic
    underline=True       # Underline
)
```

### Renderer

Screen rendering:

```python
from snakia.core.tui import RenderContext
from snakia.core.tui.render import ANSIRenderer
import sys

class StdoutTarget:
    def write(self, text: str): sys.stdout.write(text)
    def flush(self): sys.stdout.flush()

renderer = ANSIRenderer(StdoutTarget())

with RenderContext(renderer) as ctx:
    ctx.render(widget.render())
```

### Ready-made Widgets

```python
from snakia.core.tui.widgets import (
    TextWidget, BoxWidget, 
    HorizontalSplitWidget, VerticalSplitWidget
)

# Text widget
text = TextWidget("Hello", CanvasChar(fg_color="red", bold=True))

# Box widget
box = BoxWidget(10, 5, CanvasChar("█", fg_color="yellow"))

# Splitters
h_split = HorizontalSplitWidget([text1, text2], "|")
v_split = VerticalSplitWidget([h_split, box], "-")
```

## ⚡ Reactive Programming (RX)

Reactive programming system for creating responsive interfaces.

### Bindable

Reactive variables:

```python
from snakia.core.rx import Bindable, ValueChanged

# Creating a reactive variable
counter = Bindable(0)

# Subscribing to changes
def on_change(event: ValueChanged[int]):
    print(f"Counter changed from {event.old_value} to {event.new_value}")

counter.subscribe(on_change)

# Changing value
counter.set(5)  # Will call on_change
counter(10)     # Alternative syntax
```

### AsyncBindable

Asynchronous reactive variables:

```python
from snakia.core.rx import AsyncBindable

async_counter = AsyncBindable(0)

async def async_handler(event: ValueChanged[int]):
    print(f"Async counter: {event.new_value}")

await async_counter.subscribe(async_handler, run_now=True)
await async_counter.set(42)
```

### Operators

```python
from snakia.core.rx import map, filter, combine, merge

# Transformation
doubled = map(counter, lambda x: x * 2)

# Filtering
even_only = filter(counter, lambda x: x % 2 == 0)

# Combining
combined = combine(counter, doubled, lambda a, b: a + b)

# Merging streams
merged = merge(counter, async_counter)
```

## 🛠️ Utilities

### to_async

Converting synchronous functions to asynchronous:

```python
from snakia.utils import to_async

def sync_function(x):
    return x * 2

async_function = to_async(sync_function)
result = await async_function(5)
```

### nolock

Performance optimization:

```python
from snakia.utils import nolock

def busy_loop():
    while running:
        # Work
        nolock()  # Release GIL
```

### inherit

Simplified inheritance:

```python
from snakia.utils import inherit

class Base:
    def method(self): pass

class Derived(inherit(Base)):
    def method(self):
        super().method()
        # Additional logic
```

### this

Reference to current object:

```python
from snakia.utils import this

def func():
    return this()  # Returns `<function func at ...>`
```

### throw

Throwing exceptions:

```python
from snakia.utils import throw

def validate(value):
    if value < 0:
        throw(ValueError("Value must be positive"))
```

### frame

Working with frames:

```python
from snakia.utils import frame

def process_frame():
    current_frame = frame()
    # Process frame
```

## 🎭 Decorators

### inject_replace

Method replacement:

```python
from snakia.decorators import inject_replace

class Original:
    def method(self): return "original"

@inject_replace(Original, "method")
def new_method(self): return "replaced"
```

### inject_before / inject_after

Hooks before and after execution:

```python
from snakia.decorators import inject_before, inject_after

@inject_before(MyClass, "method")
def before_hook(self): print("Before method")

@inject_after(MyClass, "method") 
def after_hook(self): print("After method")
```

### singleton

Singleton pattern:

```python
from snakia.decorators import singleton

@singleton
class Database:
    def __init__(self):
        self.connection = "connected"
```

### pass_exceptions

Exception handling:

```python
from snakia.decorators import pass_exceptions

@pass_exceptions(ValueError, TypeError)
def risky_function():
    # Code that might throw exceptions
    pass
```

## 🏷️ Properties

### readonly

Read-only property:

```python
from snakia.property import readonly


class Currency:
    @readonly
    def rate(self) -> int:
        return 100


currency = Currency()
currency.rate = 200
print(currency.rate)  # Output: 100
```

### initonly

Initialization-only property:

```python
from snakia.property import initonly


class Person:
    name = initonly[str]("name")


bob = Person()
bob.name = "Bob"
print(bob.name)  # Output: "Bob"
bob.name = "not bob"
print(bob.name)  # Output: "Bob"
```

### 🏛️ classproperty

Class property:

```python
from snakia.property import classproperty

class MyClass:
    @classproperty
    def class_value(cls):
        return "class_value"
```

## 🌐 Platform Abstraction

### 🖥️ PlatformOS

Operating system abstraction:

```python
from snakia.platform import PlatformOS, OS

# Detecting current OS
current_os = OS.current()

if current_os == PlatformOS.LINUX:
    print("Running on Linux")
elif current_os == PlatformOS.ANDROID:
    print("Running on Android")
```

### 🏗️ PlatformLayer

Platform layers:

```python
from snakia.platform import LinuxLayer, AndroidLayer

# Linux layer
linux_layer = LinuxLayer()

# Android layer  
android_layer = AndroidLayer()
```

## 📦 Examples

### Health System

```python
from snakia.core.engine import Engine
from snakia.core.ecs import Component
from snakia.core.es import Event
from snakia.core.loader import Meta, Plugin, PluginProcessor
from snakia.types import Version
from pydantic import Field

class HealthComponent(Component):
    max_value: int = Field(default=100, ge=0)
    value: int = Field(default=100, ge=0)

class DamageComponent(Component):
    damage: int = Field(ge=0)
    ticks: int = Field(default=1, ge=0)

class DeathEvent(Event):
    entity: int = Field()

class HealthProcessor(PluginProcessor):
    def process(self, system):
        # Processing damage
        for entity, (damage, health) in system.get_components(
            DamageComponent, HealthComponent
        ):
            health.value -= damage.damage
            damage.ticks -= 1
            
            if damage.ticks <= 0:
                system.remove_component(entity, DamageComponent)
            
            if health.value <= 0:
                system.remove_component(entity, HealthComponent)
                self.plugin.dispatcher.publish(DeathEvent(entity=entity))

class HealthPlugin(Plugin, meta=Meta(
    name="health",
    version=Version.from_args(1, 0, 0),
    processors=(HealthProcessor,)
)):
    def on_load(self): pass
    def on_unload(self): pass

# Usage
engine = Engine()
engine.loader.register(HealthPlugin)
engine.loader.load_all()

# Creating a player
player = engine.system.create_entity(
    HealthComponent(value=100, max_value=100)
)

# Dealing damage
engine.system.add_component(player, DamageComponent(damage=25, ticks=1))

engine.start()
```

### TUI Application

```python
from snakia.core.tui import CanvasChar, RenderContext
from snakia.core.tui.render import ANSIRenderer
from snakia.core.tui.widgets import TextWidget, BoxWidget, VerticalSplitWidget
import sys

class StdoutTarget:
    def write(self, text: str): sys.stdout.write(text)
    def flush(self): sys.stdout.flush()

def main():
    # Creating widgets
    title = TextWidget("Snakia TUI", CanvasChar(fg_color="cyan", bold=True))
    content = TextWidget("Welcome to Snakia!", CanvasChar(fg_color="white"))
    box = BoxWidget(20, 5, CanvasChar("█", fg_color="green"))
    
    # Layout
    layout = VerticalSplitWidget([title, content, box], "-")
    
    # Rendering
    renderer = ANSIRenderer(StdoutTarget())
    
    with RenderContext(renderer) as ctx:
        ctx.render(layout.render())

if __name__ == "__main__":
    main()
```

## 🤝 Contributing

We welcome contributions to Snakia development! Whether you're fixing bugs, adding features, or improving documentation, your help is appreciated.

### How to Contribute

1. **Fork** the repository
2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)
3. **Make** your changes
4. **Add** tests if applicable
5. **Commit** your changes (`git commit -m 'Add amazing feature'`)
6. **Push** to the branch (`git push origin feature/amazing-feature`)
7. **Open** a Pull Request

### Development Guidelines

- Add type hints to all new code
- Write clear commit messages
- Update documentation for new features
- Test your changes thoroughly

## 🆘 Support

Need help? We're here to assist you!

- 🐛 **Bug Reports** - [GitHub Issues](https://github.com/RuJect/Snakia/issues)
- 💬 **Community Chat** - [RuJect Community Telegram](https://t.me/RuJect_Community)
- 📧 **Direct Contact** - mailto:rus07tam.uwu@gmail.com

## 📄 License

See the `LICENSE` file for details.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "snakia",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "python3, event system, ecs, reactive programming",
    "author": "rus07tam",
    "author_email": "rus07tam <rus07tam@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/a5/85/f770ec7a06e09b4d356fcfca613fd274191953d29fb08d4ac5c997f0160e/snakia-0.4.0.tar.gz",
    "platform": null,
    "description": "# \ud83d\udc0d Snakia Framework\n\n**Snakia** is a modern Python framework for creating applications with Entity-Component-System (ECS) architecture, event system, and reactive programming. Built with performance (maybe) and modularity in mind, Snakia provides a clean API for developing complex applications ranging from games to terminal user interfaces.\n\n## \ud83d\udccb Table of Contents\n\n- [\ud83c\udfaf Roadmap & TODO](#-roadmap--todo)\n- [\ud83d\ude80 Installation](#-installation)\n- [\ud83d\ude80 Quick Start](#-quick-start)\n- [\ud83c\udfd7\ufe0f Architecture](#\ufe0f-architecture)\n- [\u2699\ufe0f Core](#\ufe0f-core)\n- [\ud83c\udfaf ECS System](#-ecs-system)\n- [\ud83d\udce1 Event System (ES)](#-event-system-es)\n- [\ud83d\udd0c Plugin System](#-plugin-system)\n- [\ud83c\udfa8 TUI System](#-tui-system)\n- [\u26a1 Reactive Programming (RX)](#-reactive-programming-rx)\n- [\ud83d\udee0\ufe0f Utilities](#\ufe0f-utilities)\n- [\ud83c\udfad Decorators](#-decorators)\n- [\ud83c\udff7\ufe0f Properties](#-properties)\n- [\ud83c\udf10 Platform Abstraction](#-platform-abstraction)\n- [\ud83d\udce6 Examples](#-examples)\n- [\ud83e\udd1d Contributing](#-contributing)\n- [\ud83c\udd98 Support](#-support)\n- [\ud83d\udcc4 License](#-license)\n\n### \u2728 Key Features\n\n- \ud83c\udfd7\ufe0f **ECS Architecture** - Flexible entity-component-system for scalable game/app logic\n- \ud83d\udce1 **Event System** - Asynchronous event handling with filters and priorities\n- \ud83d\udd0c **Plugin System** - Modular plugin architecture for extensibility\n- \ud83c\udfa8 **TUI Framework** - Rich terminal user interface with reactive widgets\n- \u26a1 **Reactive Programming** - Observable data streams and reactive bindings\n- \ud83d\udee0\ufe0f **Rich Utilities** - Decorators, properties, platform abstraction, and more\n- \ud83c\udfaf **Type Safety** - Full type hints and Pydantic integration\n\n> \u26a0\ufe0f **Experimental Framework**  \n> This framework is currently in **beta/experimental stage**. Not all features are fully implemented, there might be bugs, and the API is subject to change. Use at your own risk! \ud83d\udea7\n\n## \ud83d\ude80 Installation\n\n### Prerequisites\n\n- **Python** >= 3.12\n- **pip** or **uv** (recommended) package manager\n\n### Install from PyPi (recommended)\n\n```bash\npip install snakia\n```\n\n### Install from Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/RuJect/Snakia.git\ncd Snakia\n\n# Install with pip\npip install -e .\n\n# Or with uv (recommended)\nuv sync\n```\n\n## \ud83c\udfaf Roadmap & TODO\n\nHere's what we're working on to make Snakia even better:\n\n- [ ] Plugin Isolation: restrict plugin access to only events and components statically defined in manifest\n- [ ] Async & Multithreading: implement proper async/await support and multithreading capabilities  \n- [ ] Platform Support: expand platform abstraction to support more operating systems\n- [ ] Random Implementations: add various random generations implementations\n- [ ] TUI Widgets: create more ready-to-use TUI widgets and components\n- [ ] Code Documentation: add comprehensive docstrings and inline comments\n- [ ] Documentation: create detailed API documentation and tutorials\n\n## \ud83d\ude80 Quick Start\n\n```python\nfrom snakia.core.engine import Engine\nfrom snakia.core.loader import Meta, Plugin, PluginProcessor\nfrom snakia.core.ecs import Component\nfrom snakia.types import Version\n\n# Creating a component\nclass HealthComponent(Component):\n    value: int = 100\n    max_value: int = 100\n\n# Creating a processor\nclass HealthProcessor(PluginProcessor):\n    def process(self, system):\n        for entity, (health,) in system.get_components(HealthComponent):\n            if health.value <= 0:\n                print(f\"Entity {entity} died!\")\n\n# Creating a plugin\nclass HealthPlugin(Plugin, meta=Meta(\n    name=\"health\",\n    version=Version.from_args(1, 0, 0),\n    processors=(HealthProcessor,)\n)):\n    def on_load(self): pass\n    def on_unload(self): pass\n\n# Starting the engine\nengine = Engine()\nengine.loader.register(HealthPlugin)\nengine.loader.load_all()\nengine.start()\n```\n\n## \ud83c\udfd7\ufe0f Architecture\n\nSnakia is built on a modular architecture with clear separation of concerns:\n\n```plaintext\nSnakia/\n\u251c\u2500\u2500 core/           # Framework core\n\u2502   \u251c\u2500\u2500 engine.py   # Main engine\n\u2502   \u251c\u2500\u2500 ecs/        # Entity-Component-System\n\u2502   \u251c\u2500\u2500 es/         # Event System\n\u2502   \u251c\u2500\u2500 loader/     # Plugin loading system\n\u2502   \u251c\u2500\u2500 rx/         # Reactive programming\n\u2502   \u2514\u2500\u2500 tui/        # Terminal User Interface\n\u251c\u2500\u2500 decorators/    # Decorators\n\u251c\u2500\u2500 property/      # Property system\n\u251c\u2500\u2500 platform/      # Platform abstraction\n\u251c\u2500\u2500 utils/         # Utilities\n\u251c\u2500\u2500 random/        # Random number generation\n\u251c\u2500\u2500 field/         # Typed fields\n\u2514\u2500\u2500 types/         # Special types\n```\n\n## \u2699\ufe0f Core\n\n### Engine\n\nThe central component of the framework that coordinates all systems:\n\n```python\nfrom snakia.core.engine import Engine\n\nengine = Engine()\n# Systems:\n# - engine.system    - ECS system\n# - engine.dispatcher - Event system  \n# - engine.loader    - Plugin loader\n\nengine.start()  # Start all systems\nengine.stop()   # Stop all systems\nengine.update() # Update systems\n```\n\n## \ud83c\udfaf ECS System\n\nEntity-Component-System architecture for creating flexible and performant applications.\n\n### Component\n\nBase class for all components:\n\n```python\nfrom snakia.core.ecs import Component\nfrom pydantic import Field\n\nclass PositionComponent(Component):\n    x: float = Field(default=0.0)\n    y: float = Field(default=0.0)\n\nclass VelocityComponent(Component):\n    vx: float = Field(default=0.0)\n    vy: float = Field(default=0.0)\n```\n\n### Processor\n\nProcessors handle components in the system:\n\n```python\nfrom snakia.core.ecs import Processor, System\n\nclass MovementProcessor(Processor):\n    def process(self, system: System) -> None:\n        # Get all entities with Position and Velocity\n        for entity, (pos, vel) in system.get_components(\n            PositionComponent, VelocityComponent\n        ):\n            pos.x += vel.vx\n            pos.y += vel.vy\n```\n\n### System\n\nEntity and component management:\n\n```python\n# Creating an entity with components\nentity = system.create_entity(\n    PositionComponent(x=10, y=20),\n    VelocityComponent(vx=1, vy=0)\n)\n\n# Adding a component to an existing entity\nsystem.add_component(entity, HealthComponent(value=100))\n\n# Getting entity components\npos, vel = system.get_components_of_entity(\n    entity, PositionComponent, VelocityComponent\n)\n\n# Checking for components\nif system.has_components(entity, PositionComponent, VelocityComponent):\n    print(\"Entity has position and velocity\")\n\n# Removing a component\nsystem.remove_component(entity, VelocityComponent)\n\n# Deleting an entity\nsystem.delete_entity(entity)\n```\n\n## \ud83d\udce1 Event System (ES)\n\nAsynchronous event system with filter and priority support.\n\n### Event\n\nBase class for events:\n\n```python\nfrom snakia.core.es import Event\nfrom pydantic import Field\n\nclass PlayerDiedEvent(Event):\n    player_id: int = Field()\n    cause: str = Field(default=\"unknown\")\n    ttl: int = Field(default=10)  # Event lifetime\n```\n\n### Handler\n\nEvent handlers:\n\n```python\nfrom snakia.core.es import Handler, Action\n\ndef on_player_died(event: PlayerDiedEvent) -> Action | None:\n    print(f\"Player {event.player_id} died from {event.cause}\")\n    return Action.move(1)  # Move to next handler\n```\n\n### Filter\n\nEvent filters:\n\n```python\nfrom snakia.core.es import Filter\n\ndef only_important_deaths(event: PlayerDiedEvent) -> bool:\n    return event.cause in [\"boss\", \"pvp\"]\n\n# Using a filter\n@dispatcher.on(PlayerDiedEvent, filter=only_important_deaths)\ndef handle_important_death(event: PlayerDiedEvent):\n    print(\"Important death occurred!\")\n```\n\n### Dispatcher\n\nCentral event dispatcher:\n\n```python\nfrom snakia.core.es import Dispatcher, Subscriber\n\ndispatcher = Dispatcher()\n\n# Subscribing to an event\ndispatcher.subscribe(PlayerDiedEvent, Subscriber(\n    handler=on_player_died,\n    filter=only_important_deaths,\n    priority=10\n))\n\n# Decorator for subscription\n@dispatcher.on(PlayerDiedEvent, priority=5)\ndef handle_death(event: PlayerDiedEvent):\n    print(\"Death handled!\")\n\n# Publishing an event\ndispatcher.publish(PlayerDiedEvent(player_id=123, cause=\"boss\"))\n```\n\n## \ud83d\udd0c Plugin System\n\nModular system for loading and managing plugins.\n\n### Plugin\n\nBase class for plugins:\n\n```python\nfrom snakia.core.loader import Meta, Plugin, PluginProcessor\nfrom snakia.types import Version\n\nclass MyProcessor(PluginProcessor):\n    def process(self, system):\n        # Processor logic\n        pass\n\nclass MyPlugin(Plugin, meta=Meta(\n    name=\"my_plugin\",\n    author=\"developer\",\n    version=Version.from_args(1, 0, 0),\n    processors=(MyProcessor,),\n    subscribers=()\n)):\n    def on_load(self):\n        print(\"Plugin loaded!\")\n    \n    def on_unload(self):\n        print(\"Plugin unloaded!\")\n```\n\n### Meta\n\nPlugin metadata:\n\n```python\nfrom snakia.core.loader import Meta\nfrom snakia.core.es import Subscriber\n\nmeta = Meta(\n    name=\"plugin_name\",\n    author=\"author_name\", \n    version=Version.from_args(1, 0, 0),\n    processors=(Processor1, Processor2),\n    subscribers=(\n        (EventType, Subscriber(handler, filter, priority)),\n    )\n)\n```\n\n### Loader\n\nPlugin loader:\n\n```python\nfrom snakia.core.loader import Loader\n\nloader = Loader(engine)\n\n# Registering a plugin\nloader.register(MyPlugin)\n\n# Loading all plugins\nloader.load_all()\n\n# Unloading all plugins\nloader.unload_all()\n```\n\n## \ud83c\udfa8 TUI System\n\nSystem for creating text-based user interfaces.\n\n### Widget\n\nBase class for widgets:\n\n```python\nfrom snakia.core.tui import Widget, Canvas, CanvasChar\nfrom snakia.core.rx import Bindable\n\nclass MyWidget(Widget):\n    def __init__(self):\n        super().__init__()\n        self.text = self.state(\"Hello World\")\n        self.color = self.state(CanvasChar(fg_color=\"red\"))\n    \n    def on_render(self) -> Canvas:\n        canvas = Canvas(20, 5)\n        canvas.draw_text(0, 0, self.text.value, self.color.value)\n        return canvas\n```\n\n### Canvas\n\nDrawing canvas:\n\n```python\nfrom snakia.core.tui import Canvas, CanvasChar\n\ncanvas = Canvas(80, 24)\n\n# Drawing text\ncanvas.draw_text(10, 5, \"Hello\", CanvasChar(fg_color=\"blue\"))\n\n# Drawing rectangle\ncanvas.draw_rect(0, 0, 20, 10, CanvasChar(\"\u2588\", fg_color=\"green\"))\n\n# Filling area\ncanvas.draw_filled_rect(5, 5, 10, 5, CanvasChar(\" \", bg_color=\"red\"))\n\n# Lines\ncanvas.draw_line_h(0, 0, 20, CanvasChar(\"-\"))\ncanvas.draw_line_v(0, 0, 10, CanvasChar(\"|\"))\n```\n\n### CanvasChar\n\nCharacter with attributes:\n\n```python\nfrom snakia.core.tui import CanvasChar\n\nchar = CanvasChar(\n    char=\"A\",\n    fg_color=\"red\",      # Text color\n    bg_color=\"blue\",     # Background color\n    bold=True,           # Bold\n    italic=False,        # Italic\n    underline=True       # Underline\n)\n```\n\n### Renderer\n\nScreen rendering:\n\n```python\nfrom snakia.core.tui import RenderContext\nfrom snakia.core.tui.render import ANSIRenderer\nimport sys\n\nclass StdoutTarget:\n    def write(self, text: str): sys.stdout.write(text)\n    def flush(self): sys.stdout.flush()\n\nrenderer = ANSIRenderer(StdoutTarget())\n\nwith RenderContext(renderer) as ctx:\n    ctx.render(widget.render())\n```\n\n### Ready-made Widgets\n\n```python\nfrom snakia.core.tui.widgets import (\n    TextWidget, BoxWidget, \n    HorizontalSplitWidget, VerticalSplitWidget\n)\n\n# Text widget\ntext = TextWidget(\"Hello\", CanvasChar(fg_color=\"red\", bold=True))\n\n# Box widget\nbox = BoxWidget(10, 5, CanvasChar(\"\u2588\", fg_color=\"yellow\"))\n\n# Splitters\nh_split = HorizontalSplitWidget([text1, text2], \"|\")\nv_split = VerticalSplitWidget([h_split, box], \"-\")\n```\n\n## \u26a1 Reactive Programming (RX)\n\nReactive programming system for creating responsive interfaces.\n\n### Bindable\n\nReactive variables:\n\n```python\nfrom snakia.core.rx import Bindable, ValueChanged\n\n# Creating a reactive variable\ncounter = Bindable(0)\n\n# Subscribing to changes\ndef on_change(event: ValueChanged[int]):\n    print(f\"Counter changed from {event.old_value} to {event.new_value}\")\n\ncounter.subscribe(on_change)\n\n# Changing value\ncounter.set(5)  # Will call on_change\ncounter(10)     # Alternative syntax\n```\n\n### AsyncBindable\n\nAsynchronous reactive variables:\n\n```python\nfrom snakia.core.rx import AsyncBindable\n\nasync_counter = AsyncBindable(0)\n\nasync def async_handler(event: ValueChanged[int]):\n    print(f\"Async counter: {event.new_value}\")\n\nawait async_counter.subscribe(async_handler, run_now=True)\nawait async_counter.set(42)\n```\n\n### Operators\n\n```python\nfrom snakia.core.rx import map, filter, combine, merge\n\n# Transformation\ndoubled = map(counter, lambda x: x * 2)\n\n# Filtering\neven_only = filter(counter, lambda x: x % 2 == 0)\n\n# Combining\ncombined = combine(counter, doubled, lambda a, b: a + b)\n\n# Merging streams\nmerged = merge(counter, async_counter)\n```\n\n## \ud83d\udee0\ufe0f Utilities\n\n### to_async\n\nConverting synchronous functions to asynchronous:\n\n```python\nfrom snakia.utils import to_async\n\ndef sync_function(x):\n    return x * 2\n\nasync_function = to_async(sync_function)\nresult = await async_function(5)\n```\n\n### nolock\n\nPerformance optimization:\n\n```python\nfrom snakia.utils import nolock\n\ndef busy_loop():\n    while running:\n        # Work\n        nolock()  # Release GIL\n```\n\n### inherit\n\nSimplified inheritance:\n\n```python\nfrom snakia.utils import inherit\n\nclass Base:\n    def method(self): pass\n\nclass Derived(inherit(Base)):\n    def method(self):\n        super().method()\n        # Additional logic\n```\n\n### this\n\nReference to current object:\n\n```python\nfrom snakia.utils import this\n\ndef func():\n    return this()  # Returns `<function func at ...>`\n```\n\n### throw\n\nThrowing exceptions:\n\n```python\nfrom snakia.utils import throw\n\ndef validate(value):\n    if value < 0:\n        throw(ValueError(\"Value must be positive\"))\n```\n\n### frame\n\nWorking with frames:\n\n```python\nfrom snakia.utils import frame\n\ndef process_frame():\n    current_frame = frame()\n    # Process frame\n```\n\n## \ud83c\udfad Decorators\n\n### inject_replace\n\nMethod replacement:\n\n```python\nfrom snakia.decorators import inject_replace\n\nclass Original:\n    def method(self): return \"original\"\n\n@inject_replace(Original, \"method\")\ndef new_method(self): return \"replaced\"\n```\n\n### inject_before / inject_after\n\nHooks before and after execution:\n\n```python\nfrom snakia.decorators import inject_before, inject_after\n\n@inject_before(MyClass, \"method\")\ndef before_hook(self): print(\"Before method\")\n\n@inject_after(MyClass, \"method\") \ndef after_hook(self): print(\"After method\")\n```\n\n### singleton\n\nSingleton pattern:\n\n```python\nfrom snakia.decorators import singleton\n\n@singleton\nclass Database:\n    def __init__(self):\n        self.connection = \"connected\"\n```\n\n### pass_exceptions\n\nException handling:\n\n```python\nfrom snakia.decorators import pass_exceptions\n\n@pass_exceptions(ValueError, TypeError)\ndef risky_function():\n    # Code that might throw exceptions\n    pass\n```\n\n## \ud83c\udff7\ufe0f Properties\n\n### readonly\n\nRead-only property:\n\n```python\nfrom snakia.property import readonly\n\n\nclass Currency:\n    @readonly\n    def rate(self) -> int:\n        return 100\n\n\ncurrency = Currency()\ncurrency.rate = 200\nprint(currency.rate)  # Output: 100\n```\n\n### initonly\n\nInitialization-only property:\n\n```python\nfrom snakia.property import initonly\n\n\nclass Person:\n    name = initonly[str](\"name\")\n\n\nbob = Person()\nbob.name = \"Bob\"\nprint(bob.name)  # Output: \"Bob\"\nbob.name = \"not bob\"\nprint(bob.name)  # Output: \"Bob\"\n```\n\n### \ud83c\udfdb\ufe0f classproperty\n\nClass property:\n\n```python\nfrom snakia.property import classproperty\n\nclass MyClass:\n    @classproperty\n    def class_value(cls):\n        return \"class_value\"\n```\n\n## \ud83c\udf10 Platform Abstraction\n\n### \ud83d\udda5\ufe0f PlatformOS\n\nOperating system abstraction:\n\n```python\nfrom snakia.platform import PlatformOS, OS\n\n# Detecting current OS\ncurrent_os = OS.current()\n\nif current_os == PlatformOS.LINUX:\n    print(\"Running on Linux\")\nelif current_os == PlatformOS.ANDROID:\n    print(\"Running on Android\")\n```\n\n### \ud83c\udfd7\ufe0f PlatformLayer\n\nPlatform layers:\n\n```python\nfrom snakia.platform import LinuxLayer, AndroidLayer\n\n# Linux layer\nlinux_layer = LinuxLayer()\n\n# Android layer  \nandroid_layer = AndroidLayer()\n```\n\n## \ud83d\udce6 Examples\n\n### Health System\n\n```python\nfrom snakia.core.engine import Engine\nfrom snakia.core.ecs import Component\nfrom snakia.core.es import Event\nfrom snakia.core.loader import Meta, Plugin, PluginProcessor\nfrom snakia.types import Version\nfrom pydantic import Field\n\nclass HealthComponent(Component):\n    max_value: int = Field(default=100, ge=0)\n    value: int = Field(default=100, ge=0)\n\nclass DamageComponent(Component):\n    damage: int = Field(ge=0)\n    ticks: int = Field(default=1, ge=0)\n\nclass DeathEvent(Event):\n    entity: int = Field()\n\nclass HealthProcessor(PluginProcessor):\n    def process(self, system):\n        # Processing damage\n        for entity, (damage, health) in system.get_components(\n            DamageComponent, HealthComponent\n        ):\n            health.value -= damage.damage\n            damage.ticks -= 1\n            \n            if damage.ticks <= 0:\n                system.remove_component(entity, DamageComponent)\n            \n            if health.value <= 0:\n                system.remove_component(entity, HealthComponent)\n                self.plugin.dispatcher.publish(DeathEvent(entity=entity))\n\nclass HealthPlugin(Plugin, meta=Meta(\n    name=\"health\",\n    version=Version.from_args(1, 0, 0),\n    processors=(HealthProcessor,)\n)):\n    def on_load(self): pass\n    def on_unload(self): pass\n\n# Usage\nengine = Engine()\nengine.loader.register(HealthPlugin)\nengine.loader.load_all()\n\n# Creating a player\nplayer = engine.system.create_entity(\n    HealthComponent(value=100, max_value=100)\n)\n\n# Dealing damage\nengine.system.add_component(player, DamageComponent(damage=25, ticks=1))\n\nengine.start()\n```\n\n### TUI Application\n\n```python\nfrom snakia.core.tui import CanvasChar, RenderContext\nfrom snakia.core.tui.render import ANSIRenderer\nfrom snakia.core.tui.widgets import TextWidget, BoxWidget, VerticalSplitWidget\nimport sys\n\nclass StdoutTarget:\n    def write(self, text: str): sys.stdout.write(text)\n    def flush(self): sys.stdout.flush()\n\ndef main():\n    # Creating widgets\n    title = TextWidget(\"Snakia TUI\", CanvasChar(fg_color=\"cyan\", bold=True))\n    content = TextWidget(\"Welcome to Snakia!\", CanvasChar(fg_color=\"white\"))\n    box = BoxWidget(20, 5, CanvasChar(\"\u2588\", fg_color=\"green\"))\n    \n    # Layout\n    layout = VerticalSplitWidget([title, content, box], \"-\")\n    \n    # Rendering\n    renderer = ANSIRenderer(StdoutTarget())\n    \n    with RenderContext(renderer) as ctx:\n        ctx.render(layout.render())\n\nif __name__ == \"__main__\":\n    main()\n```\n\n## \ud83e\udd1d Contributing\n\nWe welcome contributions to Snakia development! Whether you're fixing bugs, adding features, or improving documentation, your help is appreciated.\n\n### How to Contribute\n\n1. **Fork** the repository\n2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)\n3. **Make** your changes\n4. **Add** tests if applicable\n5. **Commit** your changes (`git commit -m 'Add amazing feature'`)\n6. **Push** to the branch (`git push origin feature/amazing-feature`)\n7. **Open** a Pull Request\n\n### Development Guidelines\n\n- Add type hints to all new code\n- Write clear commit messages\n- Update documentation for new features\n- Test your changes thoroughly\n\n## \ud83c\udd98 Support\n\nNeed help? We're here to assist you!\n\n- \ud83d\udc1b **Bug Reports** - [GitHub Issues](https://github.com/RuJect/Snakia/issues)\n- \ud83d\udcac **Community Chat** - [RuJect Community Telegram](https://t.me/RuJect_Community)\n- \ud83d\udce7 **Direct Contact** - mailto:rus07tam.uwu@gmail.com\n\n## \ud83d\udcc4 License\n\nSee the `LICENSE` file for details.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Modern python framework",
    "version": "0.4.0",
    "project_urls": {
        "Homepage": "https://github.com/ruject/snakia",
        "Issue Tracker": "https://github.com/ruject/snakia/issues",
        "Repository": "https://github.com/ruject/snakia"
    },
    "split_keywords": [
        "python3",
        " event system",
        " ecs",
        " reactive programming"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "acf39e15b236f436ff76202998af6d3010a8647b03ad3fdf3a758bace54f0a7c",
                "md5": "0e36b52145e480d665f9dd7a60b53c84",
                "sha256": "53aeff7821707e44382647bebd550c8c3579966ed2ffc0ff1b228c367083e9c4"
            },
            "downloads": -1,
            "filename": "snakia-0.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0e36b52145e480d665f9dd7a60b53c84",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 58346,
            "upload_time": "2025-10-26T16:29:08",
            "upload_time_iso_8601": "2025-10-26T16:29:08.321436Z",
            "url": "https://files.pythonhosted.org/packages/ac/f3/9e15b236f436ff76202998af6d3010a8647b03ad3fdf3a758bace54f0a7c/snakia-0.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a585f770ec7a06e09b4d356fcfca613fd274191953d29fb08d4ac5c997f0160e",
                "md5": "5646d0616a11bd54a62517f320961584",
                "sha256": "2a72e26a0be9922fec542698e6119cc7e31b6bf233f900e55d3fc4a2ba2dd741"
            },
            "downloads": -1,
            "filename": "snakia-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "5646d0616a11bd54a62517f320961584",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 30631,
            "upload_time": "2025-10-26T16:29:09",
            "upload_time_iso_8601": "2025-10-26T16:29:09.824073Z",
            "url": "https://files.pythonhosted.org/packages/a5/85/f770ec7a06e09b4d356fcfca613fd274191953d29fb08d4ac5c997f0160e/snakia-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-26 16:29:09",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ruject",
    "github_project": "snakia",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "annotated-types",
            "specs": [
                [
                    "==",
                    "0.7.0"
                ]
            ]
        },
        {
            "name": "networkx",
            "specs": [
                [
                    "==",
                    "3.5"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    "==",
                    "2.12.3"
                ]
            ]
        },
        {
            "name": "pydantic-core",
            "specs": [
                [
                    "==",
                    "2.41.4"
                ]
            ]
        },
        {
            "name": "typing-extensions",
            "specs": [
                [
                    "==",
                    "4.15.0"
                ]
            ]
        },
        {
            "name": "typing-inspection",
            "specs": [
                [
                    "==",
                    "0.4.2"
                ]
            ]
        }
    ],
    "lcname": "snakia"
}
        
Elapsed time: 2.46217s