# 🐍 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"
}