Metadata-Version: 2.4
Name: eventure
Version: 0.4.0
Summary: A Python library providing a robust, type-safe event system for game development and simulation.
Author-email: Enrico Stara <enrico.stara@gmail.com>
License: MIT License
        
        Copyright (c) 2025 Enrico Stara
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Requires-Python: >=3.12
Description-Content-Type: text/markdown

# Eventure

A powerful event-driven framework for simulations, games, and complex systems with comprehensive event tracking, querying, and analysis capabilities.

## Features

- **Event Management**
  - Immutable events with tick, timestamp, type, data, and unique ID attributes
  - Parent-child relationships between events for cascade tracking
  - JSON serialization for persistence and network transmission

- **Event Log & Bus**
  - EventLog: Track, save, and replay sequences of events
  - EventBus: Decouple event producers from consumers with wildcard subscriptions
  - Game state reconstruction through deterministic event replay

- **Advanced Event Querying**
  - Filter events by type, data content, or relationships
  - Analyze event cascades and parent-child structures
  - Count, group, and visualize events with detailed formatting
  - Query events by tick, root events, and other criteria

- **Ready-to-Use Examples**
  - Cryptocurrency Trading Bot: Financial simulation with market events
  - Adventure Game: Complete game state management through events

- **Developer-Friendly**
  - Type-safe API with comprehensive type hints
  - Zero dependencies (pure Python implementation)
  - Extensive test coverage
  - Detailed documentation

## Core Concepts

### Tick-Based Architecture

Eventure uses a tick-based architecture that provides several key advantages:

1. **Deterministic Execution**
   - Events within a tick are processed in a consistent, predictable order
   - Eliminates race conditions and timing-related bugs
   - Makes debugging significantly easier with reproducible scenarios

2. **Perfect State Reconstruction**
   - Any historical state can be precisely reconstructed by replaying events
   - Enables powerful debugging, testing, and analysis capabilities
   - Simplifies save/load functionality - just save events up to the current tick

3. **Simplified Testing**
   - Tests become deterministic and reproducible
   - Easy to write assertions about the state at specific ticks
   - Test complex event cascades with confidence

4. **Performance Optimization**
   - Events can be batched and processed efficiently within ticks
   - Natural support for parallel processing of events
   - Reduced overhead compared to continuous time systems

5. **Flexible Simulation Control**
   - Easily implement pause, step-forward, or fast-forward functionality
   - Run simulations at different speeds without affecting logic
   - Perfect for debugging complex scenarios or analyzing specific moments

```python
# Example: Using ticks for deterministic ordering
log.add_event("market.price_update", {"price": 100})  # Tick 1
log.advance_tick()
log.add_event("trading.buy_order", {"amount": 10})    # Tick 2

# Example: Getting state at a specific point in time
events_at_tick_5 = query.get_events_at_tick(5)
state_at_tick_5 = derive_game_state([e for e in log.events if e.tick <= 5])
```

### Event Cascade System

Eventure's event cascade system tracks relationships between events, providing several powerful capabilities:

1. **Causal Tracking**
   - Every event can have a parent event that triggered it
   - Complete traceability from cause to effect
   - Understand complex chains of interactions

2. **Debugging and Analysis**
   - Trace the root cause of any system behavior
   - Visualize complete event cascades
   - Identify unexpected side effects or event chains

3. **Rich Query Capabilities**
   - Filter events by their relationships
   - Find all events triggered by a specific root event
   - Analyze patterns in event propagation

4. **System Understanding**
   - Map complex interactions between system components
   - Document emergent behaviors
   - Improve system design through relationship analysis

```python
# Creating related events
def on_enemy_defeated(event):
    # This event will be linked to the parent event
    bus.publish("treasure.drop", {"item": "gold_coins"}, parent_event=event)
    bus.publish("experience.gain", {"amount": 100}, parent_event=event)

# Querying related events
root_event = query.get_event_by_id("0-ABCD-1")
cascade = query.get_cascade(root_event)  # All events triggered by this event
query.print_single_cascade(root_event)   # Visualize the cascade
```

## Installation

```bash
# Using pip
pip install eventure

# Using uv (recommended)
uv add eventure
```

## Core Components

### Event

The fundamental unit representing something that happened:

```python
from eventure import Event

# Create an event
event = Event(
    tick=0, 
    timestamp=time.time(), 
    type="user.login", 
    data={"user_id": 123, "ip": "192.168.1.1"}
)

# Events have unique IDs and can be serialized
print(f"Event ID: {event.id}")  # Format: {tick}-{typeHash}-{sequence}
json_str = event.to_json()
```

### EventLog

Tracks, stores, and manages events in a time-ordered sequence:

```python
from eventure import EventLog

# Create an event log
log = EventLog()

# Add events to the log
event = log.add_event("user.login", {"user_id": 123})
log.advance_tick()  # Move to next discrete time step
log.add_event("user.action", {"user_id": 123, "action": "view_profile"})

# Create child events (establishing causal relationships)
parent = log.add_event("combat.start", {"player": "hero", "enemy": "dragon"})
child = log.add_event("combat.attack", {"damage": 15}, parent_event=parent)

# Save and load event history
log.save_to_file("game_events.json")
new_log = EventLog.load_from_file("game_events.json")
```

### EventBus

Manages event publication and subscription:

```python
from eventure import EventBus

# Create an event bus connected to a log
bus = EventBus(log)

# Subscribe to specific events
def on_login(event):
    print(f"User {event.data['user_id']} logged in")
    
unsubscribe = bus.subscribe("user.login", on_login)

# Subscribe with wildcards
bus.subscribe("user.*", lambda e: print(f"User event: {e.type}"))
bus.subscribe("*.error", lambda e: print(f"Error: {e.data['message']}"))

# Publish events
bus.publish("user.login", {"user_id": 456})

# Unsubscribe when done
unsubscribe()
```

### EventQuery

Powerful API for querying, analyzing, and visualizing events:

```python
from eventure import EventQuery

# Create a query interface for an event log
query = EventQuery(log)

# Filter events
combat_events = query.get_events_by_type("combat.attack")
dragon_events = query.get_events_by_data("enemy", "dragon")

# Analyze relationships
child_events = query.get_child_events(parent_event)
cascade = query.get_cascade_events(root_event)

# Count and group
type_counts = query.count_events_by_type()
print(f"Combat events: {type_counts.get('combat.attack', 0)}")

# Get events by tick or relationship
tick5_events = query.get_events_at_tick(5)
root_events = query.get_root_events()

# Visualize events and cascades
query.print_event_cascade()  # All events organized by tick
query.print_single_cascade(root_event)  # Show a specific cascade
query.print_event_details(event)  # Show details of a single event
```

## Example Applications

Eventure includes two complete example applications demonstrating real-world usage:

### Cryptocurrency Trading Bot

A simulated trading system showing market events, trading signals, and order execution:

```python
from examples.crypto_trading_bot import CryptoTradingBot

# Create and run a trading simulation
bot = CryptoTradingBot()
bot.run_simulation()

# Query interesting patterns from the event log
query = EventQuery(bot.event_log)
buy_signals = query.get_events_by_data("signal", "BUY")
```

Key features demonstrated:
- Market simulation with price and volume updates
- Trading strategy implementation via events
- Order creation and execution
- Portfolio tracking
- Event-based system analysis

### Adventure Game

A text-based adventure game showing game state management:

```python
from examples.adventure_game import AdventureGame

# Create and run a game
game = AdventureGame()
game.run_game()

# Analyze game events
query = EventQuery(game.event_log)
combat_events = query.get_events_by_type("combat.start")
treasure_events = query.get_events_by_type("treasure.found")
```

Key features demonstrated:
- Room navigation and discovery
- Item collection and inventory management
- Enemy encounters and combat
- Event cascades (e.g., entering a room triggers discoveries)
- Game state derivation from events

## EventQuery API in Detail

The EventQuery API provides a consistent set of methods for analyzing and visualizing events:

### Filtering Events

```python
# By event type
strategy_signals = query.get_events_by_type("strategy.signal")

# By data content
buy_signals = query.get_events_by_data("signal", "BUY")
dragon_encounters = query.get_events_by_data("enemy", "dragon")

# By tick
tick_3_events = query.get_events_at_tick(3)

# Root events (with no parent or parent in previous tick)
root_events = query.get_root_events()
```

### Relationship Queries

```python
# Direct children of an event
children = query.get_child_events(parent_event)

# Complete cascade (parent, children, grandchildren, etc.)
full_cascade = query.get_cascade_events(root_event)
```

### Analysis Methods

```python
# Count events by type
counts = query.count_events_by_type()
print(f"Total combat events: {sum(counts.get(t, 0) for t in counts if t.startswith('combat.'))}")
```

### Visualization

```python
# Print all events organized by tick
query.print_event_cascade()

# Print a specific event cascade
query.print_single_cascade(root_event)

# Print details of a specific event
query.print_event_details(event)
```

## Event Visualization Examples

The EventQuery API provides powerful visualization capabilities for event cascades. Here are some examples from the included Adventure Game example:

#### Room Entry and Combat Sequence

```
┌─── TICK 4 ───┐
│
  ↓ room.enter (caused by: player.move @ tick 3)
    ID: 4-FADA-1
    Data:
      room: treasury
      description: Glittering treasures fill this heavily guarded room.
    │
    └─ enemy.encounter
    │ ID: 4-ADCF-1
    │ Data:
    │   enemy: dragon
    │   message: A dragon appears before you!
└───────────────┘

┌─── TICK 5 ───┐
│
  ↓ combat.start (caused by: enemy.encounter @ tick 4)
    ID: 5-ABAA-1
    Data:
      enemy: dragon
      enemy_health: 100
      message: Combat with dragon begins!
│
  ↓ combat.round (caused by: enemy.encounter @ tick 4)
    ID: 5-BDBB-1
    Data:
      enemy: dragon
      round: 1
      message: Round 1 against dragon!
    │
    └─ combat.damage_dealt
    │ ID: 5-DDDF-1
    │ Data:
    │   enemy: dragon
    │   amount: 18
    │   message: You hit the dragon for 18 damage!
└───────────────┘
```

This visualization shows:
- Events organized by tick
- Parent-child relationships with indentation
- Causal connections between events (shown with arrows)
- Complete event data for analysis

To generate these visualizations in your code:

```python
# Print all events in the log organized by tick
query.print_event_cascade()

# Print a specific cascade starting from a root event
query.print_single_cascade(root_event)

# Print details of a single event
query.print_event_details(event)
```

## Advanced Usage

### Event Replay and State Reconstruction

One of Eventure's most powerful features is the ability to reconstruct state by replaying events:

```python
# State can be derived entirely from events
def derive_game_state(events):
    state = {"health": 100, "inventory": [], "location": "start"}
    
    for event in events:
        if event.type == "player.damage":
            state["health"] -= event.data["amount"]
        elif event.type == "item.pickup":
            state["inventory"].append(event.data["item"])
        elif event.type == "player.move":
            state["location"] = event.data["destination"]
            
    return state

# Current state from all events
current_state = derive_game_state(log.events)

# Historical state (state at tick 5)
tick_5_events = [e for e in log.events if e.tick <= 5]
historical_state = derive_game_state(tick_5_events)
```

### Custom Event Handlers with EventBus

```python
# Create specialized handlers
def combat_handler(event):
    if event.data.get("enemy_health", 0) <= 0:
        # Generate a cascade event
        bus.publish("enemy.defeated", 
                   {"enemy": event.data["enemy"]},
                   parent_event=event)

# Subscribe to events
bus.subscribe("combat.attack", combat_handler)
```

## API Reference

For the complete API documentation, see the [API Reference](src/README.md).

## Development

### Setup Development Environment

```bash
# Clone the repository
git clone https://github.com/yourusername/eventure.git
cd eventure

# Install development dependencies
uv sync --all-extras
```

### Running Tests

```bash
# Run all tests
just test
```

## License

[MIT License](LICENSE)