gtpyhop


Namegtpyhop JSON
Version 1.3.0 PyPI version JSON
download
home_pageNone
SummaryA Goal-Task-Network planning package written in Python
upload_time2025-08-22 16:42:00
maintainerNone
docs_urlNone
authorNone
requires_python>=3
licenseClear BSD License
keywords artificial intelligence automated planning htn planning
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # GTPyhop version 1.3.0

[![Python Version](https://img.shields.io/badge/python-3%2B-blue.svg)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/license-Clear%20BSD-green.svg)](https://github.com/PCfVW/GTPyhop/blob/pip/LICENSE.txt)

GTPyhop is a task-planning system based on [Pyhop](https://bitbucket.org/dananau/pyhop/src/master/), but generalized to plan for both goals and tasks.

[Dana Nau](https://www.cs.umd.edu/~nau/) is the original author of GTPyhop.

## The pip Branch

[This pip branch](https://github.com/PCfVW/GTPyhop/tree/pip) is forked from [Dana Nau's GTPyhop main branch](https://github.com/dananau/GTPyhop) and refactored for PyPI distribution.

The file tree structure of [this pip branch](https://github.com/PCfVW/GTPyhop/tree/pip), produced with the help of [_GithubTree](https://github.com/mgks/GitHubTree), is the following:

```
πŸ“„ LICENSE.txt
πŸ“„ pyproject.toml
πŸ“„ README.md
πŸ“ src/
    └── πŸ“ gtpyhop/
        β”œβ”€β”€ πŸ“„ __init__.py
        β”œβ”€β”€ πŸ“ examples/
            β”œβ”€β”€ πŸ“„ __init__.py
            β”œβ”€β”€ πŸ“„ backtracking_htn.py
            β”œβ”€β”€ πŸ“ blocks_goal_splitting/
                β”œβ”€β”€ πŸ“„ __init__.py
                β”œβ”€β”€ πŸ“„ actions.py
                β”œβ”€β”€ πŸ“„ examples.py
                β”œβ”€β”€ πŸ“„ methods.py
                └── πŸ“„ README.txt
            β”œβ”€β”€ πŸ“ blocks_gtn/
                β”œβ”€β”€ πŸ“„ __init__.py
                β”œβ”€β”€ πŸ“„ actions.py
                β”œβ”€β”€ πŸ“„ examples.py
                β”œβ”€β”€ πŸ“„ methods.py
                └── πŸ“„ README.txt
            β”œβ”€β”€ πŸ“ blocks_hgn/
                β”œβ”€β”€ πŸ“„ __init__.py
                β”œβ”€β”€ πŸ“„ actions.py
                β”œβ”€β”€ πŸ“„ examples.py
                └── πŸ“„ methods.py
            β”œβ”€β”€ πŸ“ blocks_htn/
                β”œβ”€β”€ πŸ“„ __init__.py
                β”œβ”€β”€ πŸ“„ actions.py
                β”œβ”€β”€ πŸ“„ examples.py
                └── πŸ“„ methods.py
            β”œβ”€β”€ πŸ“„ logistics_hgn.py
            β”œβ”€β”€ πŸ“„ pyhop_simple_travel_example.py
            β”œβ”€β”€ πŸ“„ regression_tests.py
            β”œβ”€β”€ πŸ“„ simple_hgn.py
            β”œβ”€β”€ πŸ“„ simple_htn_acting_error.py
            └── πŸ“„ simple_htn.py
        β”œβ”€β”€ πŸ“„ logging_system.py
        β”œβ”€β”€ πŸ“„ main.py
        └── πŸ“ test_harness/
            β”œβ”€β”€ πŸ“„ __init__.py
            └── πŸ“„ test_harness.py
```

## Installation from PyPI (Recommended: Version 1.3.0)

**GTPyhop 1.3.0 is the latest version with thread-safe sessions and enhanced reliability.** For new projects, especially those requiring concurrent planning, use 1.3.0:

```bash
pip install gtpyhop>=1.3.0
```

For basic single-threaded planning, any version works:
```bash
pip install gtpyhop
```

[uv](https://docs.astral.sh/uv/) can of course be used if you prefer:

```bash
uv pip install gtpyhop
```

## Installation from github

Alternatively, you can directly install from github:

```bash
git clone -b pip https://github.com/PCfVW/GTPyhop.git
cd GTPyhop
pip install .
```

## Testing your installation

We suggest you give gtpyhop a try straight away; open a terminal and start an interactive python session:
```bash
python
```

.. and import gtpyhop to run the regression tests:

```python
# Import the main GTPyhop planning system
import gtpyhop
```

The following should be printed in your terminal:

```code
Imported GTPyhop version 1.3.0
Messages from find_plan will be prefixed with 'FP>'.
Messages from run_lazy_lookahead will be prefixed with 'RLL>'.
Using session-based architecture with structured logging.
```

Now import the regression tests module:

```python
from gtpyhop.examples import regression_tests
```

Be prepared to see a lot of information on the screen about the examples and how to solve them, with different levels of verbosity; with this in mind, run the regression tests:

```python
# Run legacy regression tests (backward compatible)
regression_tests.main()

# Or run session-based regression tests (recommended for 1.3.0+)
regression_tests.main_session()
```

The last line printed in your terminal should be:

```code
Finished without error.
```

**πŸ†• New in 1.3.0:** You can also run regression tests from the command line:

```bash
# Legacy mode
python -m gtpyhop.examples.regression_tests

# Session mode (thread-safe)
python -m gtpyhop.examples.regression_tests --session
```

Happy Planning!

## πŸ†• New in 1.3.0: Thread-Safe Sessions

**GTPyhop 1.3.0 introduces session-based, thread-safe planning** that enables reliable concurrent execution and isolated planning contexts. This is a major architectural enhancement while maintaining 100% backward compatibility.

### Key Benefits
- **Thread-safe concurrent planning**: Multiple planners can run simultaneously without interference
- **Isolated execution contexts**: Each session has its own configuration, logs, and statistics
- **Structured logging system**: Programmatic access to planning traces, statistics, and debugging information
- **Timeout management**: Built-in timeout enforcement and resource management
- **Session persistence**: Save and restore planning sessions across runs

### Quick Start with Sessions
```python
import gtpyhop

# Create a Domain and define actions/methods (same as before)
my_domain = gtpyhop.Domain('my_domain')
# ... define actions and methods ...

# NEW: Use session-based planning for thread safety
with gtpyhop.PlannerSession(domain=my_domain, verbose=1) as session:
    with session.isolated_execution():
        result = session.find_plan(state, [('transport', 'obj1', 'loc2')])
        if result.success:
            print(result.plan)
```

πŸ“– **For detailed examples, concurrent planning patterns, and complete API reference, see [GTPyhop-1.3.0-Thread-Safe-Sessions.md](https://github.com/PCfVW/GTPyhop/blob/pip/GTPyhop-1.3.0-Thread-Safe-Sessions.md)**

## Usage

You have successfully installed and tested gtpyhop; it's time to declare your own planning problems in gtpyhop.

### Very first HTN example

The key pattern is: create a Domain β†’ define actions/methods β†’ declare them β†’ use gtpyhop.find_plan() to solve problems.

In the first three steps, we give simple illustrations on Domain creation, action and task method definition, and how to declare them; in step 4 below, you'll find the code for a complete example.

**1. First, create a Domain to hold your definitions**

```python
import gtpyhop

# Create a Domain
gtpyhop.Domain('my_domain')
```

**2. Define Actions**

Actions are atomic operations that directly modify a state: actions are Python functions where the first argument is the current `state`, and the others are the action's arguments telling what changes the action shall bring to the state.

For example, the function my_action(state, arg1, arg2) below implements the action ('my_action', arg1, arg2). In the following code, `arg1` is used as an object key to check and modify its position, while `arg2` is used both as a condition to check against and as a key to update the status:

```python
def my_action(state, arg1, arg2):
    # Check preconditions using arg1 and arg2
    if state.pos[arg1] == arg2:
        # Modify state using arg1 and arg2
        state.pos[arg1] = 'new_location'
        state.status[arg2] = 'updated'
        return state  # Success
    return False  # Failure

# Declare actions
gtpyhop.declare_actions(my_action, another_action)
```

**3. Define Task Methods**

During planning, Task methods decompose compound tasks into subtasks (which shall be further decomposed) and actions (whose Python functions will be executed).

Task methods are also Python functions where the first argument is the current `state`, and the others can be passed to the subtasks and actions.

In the following code, `arg1` is used as an argument to the subtasks (perhaps specifying what object to work with), while `arg2` is used as an argument to the action (perhaps specifying a target location or condition):

```python
def method_for_task(state, arg1, arg2):
    # Check if this method is applicable
    if some_condition:
        # Return list of subtasks/actions
        return [('subtask1', arg1), ('action1', arg2)]
    return False  # Method not applicable

# Declare task methods
gtpyhop.declare_task_methods('task_name', method_for_task, alternative_method)
```

**4. Here is a complete example:**

```python
import gtpyhop

# Domain creation
gtpyhop.Domain('my_domain')

# Define state
state = gtpyhop.State('initial_state')
state.pos = {'obj1': 'loc1', 'obj2': 'loc2'}

# Actions
def move(state, obj, target):
    if obj in state.pos:
        state.pos[obj] = target
        return state
    return False

gtpyhop.declare_actions(move)

# Task methods
def transport(state, obj, destination):
    current = state.pos[obj]
    if current != destination:
        return [('move', obj, destination)]
    return []

gtpyhop.declare_task_methods('transport', transport)

# Find plan
gtpyhop.set_verbose_level(1)
plan = gtpyhop.find_plan(state, [('transport', 'obj1', 'loc2')])
print(plan)
```

Put this code in a file, say `my_very_first_htn_example.py`, and run it from a terminal:

```bash
python my_very_first_htn_example.py
```

Does it run correctly? Increase the verbosity level to 2 or 3 and run it again to see more information about the planning process.

### πŸ†• Session-Based Version (Recommended for 1.3.0+)

For better isolation and thread safety, use the session-based approach:

```python
import gtpyhop

# Domain creation (same as above)
my_domain = gtpyhop.Domain('my_domain')
state = gtpyhop.State('initial_state')
state.pos = {'obj1': 'loc1', 'obj2': 'loc2'}

# Define actions and methods (same as above)
def move(state, obj, target):
    if obj in state.pos:
        state.pos[obj] = target
        return state
    return False

gtpyhop.declare_actions(move)

def transport(state, obj, destination):
    current = state.pos[obj]
    if current != destination:
        return [('move', obj, destination)]
    return []

gtpyhop.declare_task_methods('transport', transport)

# NEW: Use session-based planning
with gtpyhop.PlannerSession(domain=my_domain, verbose=1) as session:
    with session.isolated_execution():
        result = session.find_plan(state, [('transport', 'obj1', 'loc2')])
        if result.success:
            print("Plan found:", result.plan)
            print("Planning stats:", result.stats)

            # NEW: Access structured logs
            logs = session.logger.get_logs()
            print(f"Generated {len(logs)} log entries during planning")
        else:
            print("Planning failed:", result.error)
```

**Benefits of the session approach:**
- Thread-safe for concurrent use
- Isolated configuration per session
- Built-in timeout and resource management
- Structured result objects with statistics
- **Comprehensive logging system** with programmatic access to planning traces
- Session persistence capabilities

### πŸ”„ Migration from Pre-1.3.0 Versions

**Existing code continues to work unchanged** - GTPyhop 1.3.0 maintains 100% backward compatibility.

**To leverage 1.3.0 features:**
1. **For single-threaded code**: No changes required, but consider sessions for better structure
2. **For concurrent code**: Migrate to `PlannerSession` to avoid race conditions
3. **For production systems**: Use sessions for timeout management and structured logging

**Simple migration pattern:**
```python
# Before (still works)
plan = gtpyhop.find_plan(state, tasks)

# After (recommended)
with gtpyhop.PlannerSession(domain=my_domain) as session:
    with session.isolated_execution():
        result = session.find_plan(state, tasks)
        plan = result.plan if result.success else None
```

### πŸ“‹ Version Selection Guide

| Use Case | Recommended Version | Why |
|----------|-------------------|-----|
| **New projects** | **1.3.0** | Latest features, thread safety, better error handling |
| **Concurrent/parallel planning** | **1.3.0** | Thread-safe sessions prevent race conditions |
| **Production systems** | **1.3.0** | Timeout management, structured logging, persistence |
| **Web APIs/servers** | **1.3.0** | Isolated sessions per request, timeout handling |
| **Educational/simple scripts** | Any version | All versions support basic planning |
| **Legacy code maintenance** | Keep current | All versions are backward compatible |

### Additional Information

Please read [Dana's additional information](https://github.com/dananau/GTPyhop/blob/main/additional_information.md) of how to implement:
- [States](https://github.com/dananau/GTPyhop/blob/main/additional_information.md#states)
- [Actions](https://github.com/dananau/GTPyhop/blob/main/additional_information.md#actions)
- [Tasks and task methods](https://github.com/dananau/GTPyhop/blob/main/additional_information.md#3-tasks-and-task-methods)
- [Goals and goal methods](https://github.com/dananau/GTPyhop/blob/main/additional_information.md#4-goals-and-goal-methods)
- ...and much more about GTPyhop!

## Examples

GTPyhop includes comprehensive examples demonstrating various planning techniques. **All examples support both legacy and session modes** for maximum flexibility and thread safety.

### πŸš€ Running Examples

**All examples support dual-mode execution:**

```bash
# Legacy mode (backward compatible)
python -m gtpyhop.examples.simple_htn

# Session mode (thread-safe, recommended for 1.3.0+)
python -m gtpyhop.examples.simple_htn --session

# Session mode with custom verbosity and no pauses
python -m gtpyhop.examples.simple_htn --session --verbose 2 --no-pauses
```

**Command-line arguments (available in all migrated examples):**
- `--session`: Enable thread-safe session mode
- `--verbose N`: Set verbosity level (0-3, default: 1 in session mode)
- `--no-pauses`: Skip interactive pauses for automated testing

### πŸ“‹ Available Examples

#### **Simple Examples** (Basic concepts and techniques)

| Example | Description | Key Features |
|---------|-------------|--------------|
| `simple_htn.py` | Basic hierarchical task networks | HTN planning, verbosity levels, execution |
| `simple_hgn.py` | Basic hierarchical goal networks | HGN planning, goal-oriented tasks |
| `backtracking_htn.py` | Backtracking demonstration | Method failure handling, alternative paths |
| `simple_htn_acting_error.py` | Error handling patterns | Execution failures, replanning |
| `logistics_hgn.py` | Logistics domain planning | Multi-goal planning, transportation |
| `pyhop_simple_travel_example.py` | Travel planning | Basic domain modeling |

#### **Complex Block World Examples** (Advanced planning scenarios)

| Example | Description | Key Features |
|---------|-------------|--------------|
| `blocks_htn/` | Hierarchical task networks | Complex HTN methods, block manipulation |
| `blocks_hgn/` | Hierarchical goal networks | Goal decomposition, multigoals |
| `blocks_gtn/` | Goal task networks | Mixed task/goal planning |
| `blocks_goal_splitting/` | Goal splitting methodology | Built-in goal decomposition methods |

### πŸ§ͺ Testing Examples

**Run all examples automatically:**

```bash
# Test all examples in both modes
python test_migration.py

# Test only session mode
python test_migration.py --mode session

# Test only legacy mode
python test_migration.py --mode legacy
```

**Run regression tests:**

```bash
# Legacy regression tests
python -m gtpyhop.examples.regression_tests

# Session-based regression tests
python -m gtpyhop.examples.regression_tests --session
```

### πŸ’‘ Example Usage Patterns

**Interactive exploration:**
```bash
# Run with pauses to examine output step by step
python -m gtpyhop.examples.blocks_htn.examples --session --verbose 3
```

**Automated testing:**
```bash
# Run without pauses for scripts/CI
python -m gtpyhop.examples.blocks_htn.examples --session --no-pauses
```

**Concurrent planning (session mode only):**
```python
import threading
import gtpyhop

# Load example Domain
from gtpyhop.examples.blocks_htn import actions, methods

def plan_worker(session_id, state, goals):
    with gtpyhop.PlannerSession(domain=the_domain, verbose=1) as session:
        with session.isolated_execution():
            result = session.find_plan(state, goals)
            print(f"Session {session_id}: {result.plan}")

# Run multiple planners concurrently
threads = []
for i in range(3):
    t = threading.Thread(target=plan_worker, args=(i, initial_state, goals))
    threads.append(t)
    t.start()

for t in threads:
    t.join()
```

## Structured Logging System

GTPyhop 1.3.0 introduces a comprehensive structured logging system that replaces traditional print statements with configurable, thread-safe logging. This system provides programmatic access to planning logs, statistics, and debugging information.

### 🎯 Why Structured Logging?

**Traditional challenges:**
- Print statements mixed with actual output
- No programmatic access to planning information
- Difficult to filter or analyze planning traces
- Thread safety issues in concurrent scenarios

**Structured logging benefits:**
- **Programmatic access**: Query and analyze logs programmatically
- **Thread isolation**: Each session maintains separate logs
- **Configurable output**: Control verbosity and formatting
- **Performance monitoring**: Built-in statistics and performance metrics
- **Backward compatibility**: Existing print-based output still works

### πŸ”§ How It Works

The logging system operates in both legacy and session modes:

**Legacy Mode:** Uses global logging with backward-compatible print output
**Session Mode:** Each `PlannerSession` has isolated logging with structured data collection

### πŸ“Š Log Levels and Components

**Available log levels:**
- `DEBUG` (0): Detailed debugging information
- `INFO` (1): General planning information
- `WARNING` (2): Warning messages
- `ERROR` (3): Error conditions

**Common components:**
- `FP`: Messages from `find_plan()`
- `RLL`: Messages from `run_lazy_lookahead()`
- `domain`: Domain-related operations
- `session`: Session management
- `stdout_capture`: Captured print statements

### πŸ’» Basic Usage Examples

**Import note:** All logging classes and functions are available directly from the main `gtpyhop` module:

```python
import gtpyhop

# Logging classes are available as gtpyhop.LogLevel, gtpyhop.StructuredLogger, etc.
# Or import specific components:
from gtpyhop import LogLevel, StructuredLogger, get_logging_stats
```

#### **Session Mode Logging (Recommended)**

```python
import gtpyhop

# Create session with logging
with gtpyhop.PlannerSession(domain=my_domain, verbose=2) as session:
    with session.isolated_execution():
        result = session.find_plan(state, goals)

        # Access structured logs
        logs = session.logger.get_logs()  # Get all INFO+ logs
        debug_logs = session.logger.get_logs(min_level=gtpyhop.LogLevel.DEBUG)

        # Print log summary
        print(f"Generated {len(logs)} log entries")
        for log in logs:
            print(f"[{log['level']}] {log['component']}: {log['message']}")
```

#### **Custom Log Handlers**

```python
import gtpyhop

# Create custom logger
logger = gtpyhop.StructuredLogger("my_session")

# Add custom stdout handler with formatting
custom_handler = gtpyhop.StdoutLogHandler("[{level}] {component}: {message}")
logger.add_handler(custom_handler)

# Log custom messages
logger.info("planning", "Starting plan search", state_size=len(state.pos))
logger.debug("search", "Exploring method", method_name="transport_by_truck")
```

#### **Programmatic Log Analysis**

```python
# Run planning with logging
with gtpyhop.PlannerSession(domain=logistics_domain, verbose=3) as session:
    with session.isolated_execution():
        result = session.find_plan(initial_state, goals)

        # Analyze logs
        logs = session.logger.get_logs()

        # Count log entries by component
        component_counts = {}
        for log in logs:
            component = log['component']
            component_counts[component] = component_counts.get(component, 0) + 1

        print("Log summary by component:")
        for component, count in component_counts.items():
            print(f"  {component}: {count} entries")

        # Find error logs
        error_logs = [log for log in logs if log['level'] == 'ERROR']
        if error_logs:
            print(f"Found {len(error_logs)} errors:")
            for error in error_logs:
                print(f"  {error['message']}")
```

### 🧡 Thread-Safe Concurrent Logging

Each session maintains isolated logs, making concurrent planning safe:

```python
import threading
import gtpyhop

def concurrent_planner(session_id, domain, state, goals):
    """Each thread gets isolated logging."""
    with gtpyhop.PlannerSession(domain=domain, verbose=2) as session:
        with session.isolated_execution():
            result = session.find_plan(state, goals)

            # Each session has separate logs
            logs = session.logger.get_logs()
            print(f"Session {session_id}: {len(logs)} log entries")

            return result, logs

# Run multiple planners concurrently
threads = []
results = {}

for i in range(3):
    def worker(session_id=i):
        result, logs = concurrent_planner(session_id, domain, state, goals)
        results[session_id] = {"result": result, "logs": logs}

    t = threading.Thread(target=worker)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

# Analyze results from each session
for session_id, data in results.items():
    print(f"Session {session_id}: {len(data['logs'])} logs, "
          f"plan length: {len(data['result'].plan) if data['result'].success else 'failed'}")
```

### πŸ“ˆ Performance Monitoring

The logging system includes built-in performance monitoring:

```python
import gtpyhop

with gtpyhop.PlannerSession(domain=my_domain, verbose=2) as session:
    with session.isolated_execution():
        result = session.find_plan(state, goals)

        # Get logging statistics
        stats = gtpyhop.get_logging_stats(session.logger)

        print(f"Logging Performance:")
        print(f"  Total entries: {stats.total_entries}")
        print(f"  Memory usage: {stats.memory_usage_mb:.2f} MB")
        print(f"  Entries by level: {stats.entries_by_level}")
```

### πŸ”„ Legacy Mode Compatibility

The logging system maintains backward compatibility with existing code:

```python
# Legacy code continues to work
gtpyhop.verbose = 2
plan = gtpyhop.find_plan(state, goals)  # Prints to stdout as before

# But you can also access logs programmatically
logger = gtpyhop.get_logger("default")  # Get default session logger
logs = logger.get_logs()
print(f"Legacy planning generated {len(logs)} log entries")
```

### πŸ› οΈ Advanced Features

#### **Stdout Capture**

Capture and log print statements from legacy code:

```python
logger = gtpyhop.StructuredLogger("capture_session")

with logger.capture_stdout() as captured:
    # Any print statements here are captured and logged
    print("This will be captured")
    gtpyhop.find_plan(state, goals)  # Legacy prints captured

# Captured output is now in structured logs
logs = logger.get_logs()
stdout_logs = [log for log in logs if log['component'] == 'stdout_capture']
```

#### **Custom Log Filtering**

```python
# Filter logs by component and level
def filter_planning_logs(logs, component_filter=None, min_level='INFO'):
    filtered = []
    for log in logs:
        if component_filter and log['component'] != component_filter:
            continue
        if log['level'] not in ['DEBUG', 'INFO', 'WARNING', 'ERROR'][
            ['DEBUG', 'INFO', 'WARNING', 'ERROR'].index(min_level):]:
            continue
        filtered.append(log)
    return filtered

# Usage
planning_logs = filter_planning_logs(logs, component_filter='FP', min_level='INFO')
```

### πŸŽ“ Integration with Examples

All migrated examples support structured logging in session mode:

```bash
# Run with high verbosity to see detailed logs
python -m gtpyhop.examples.blocks_htn.examples --session --verbose 3

# The logs are available programmatically when using session mode
```

**Example integration in your code:**

```python
# Import any migrated example domain
from gtpyhop.examples.blocks_htn import the_domain, actions, methods

# Use with structured logging
with gtpyhop.PlannerSession(domain=the_domain, verbose=2) as session:
    with session.isolated_execution():
        result = session.find_plan(initial_state, goals)

        # Access detailed planning logs
        logs = session.logger.get_logs()
        method_calls = [log for log in logs if 'method' in log.get('context', {})]
        print(f"Called {len(method_calls)} methods during planning")
```

### πŸ“š Documentation Structure

- **README.md** (this file): Installation, basic usage, and overview of all features
- **[GTPyhop-1.3.0-Thread-Safe-Sessions.md](https://github.com/PCfVW/GTPyhop/tree/pipGTPyhop-1.3.0-Thread-Safe-Sessions.md)**: Comprehensive guide to 1.3.0 session-based architecture
  - Detailed concurrent planning examples
  - Complete API reference for session management
  - Migration guide from global API to sessions
  - Performance considerations and best practices
- **[Dana's additional information](https://github.com/dananau/GTPyhop/blob/main/additional_information.md)**: Core GTPyhop concepts (states, actions, goals, methods)

## New Features

### Iterative Planning Strategy

[This pip branch](https://github.com/PCfVW/GTPyhop/tree/pip) introduces a new iterative planning strategy that enhances the planner's capabilities for large planning scenarios; it is the default strategy.

- How it works: Uses an explicit stack data structure
- Memory usage: More memory-efficient, no call stack buildup
- Limitations: No recursion limit constraints
- Backtracking: Explicit stack management for exploring alternatives
- Use cases:
    - Large planning problems that might exceed recursion limits
    - Memory-constrained environments
    - Production systems requiring reliability

Once gtpyhop is imported, Dana Nau's original recursive strategy can be set by calling:

```python
set_recursive_planning(True)  # Planning strategy now is recursive
```

Recursive Planning Strategy:
- How it works: Uses Python's call stack with recursive function calls
- Memory usage: Each recursive call adds a frame to the call stack
- Limitations: Limited by Python's recursion limit (default 1000)
- Backtracking: Natural backtracking through function returns
- Use cases:
    - Small to medium planning problems
    - When you need to see traditional backtracking behavior
    - Educational purposes or debugging

Of course you can get back to the iterative planning strategy by calling:

```python
set_recursive_planning(False)  # Planning strategy now is iterative
```

### New Functions

#### Functions Added in 1.3.0 (Thread-Safe Sessions)
**Session Management:**
- `PlannerSession` (class) - Isolated, thread-safe planning context
- `create_session`, `get_session`, `destroy_session`, `list_sessions` - Session lifecycle management
- `PlanningTimeoutError` (exception) - Timeout handling for session-scoped operations

**Session Persistence:**
- `SessionSerializer` (class), `restore_session`, `restore_all_sessions` - Session persistence and recovery
- `set_persistence_directory`, `get_persistence_directory` - Configure auto-save/recovery

**Enhanced Planning:**
- `session.find_plan()` - Per-session planning with timeout and expansion limits
- `session.isolated_execution()` - Context manager for safe global state management

#### Functions Added in 1.2.1 (Iterative Planning & Utilities)
**Domain Management:**
- `print_domain_names`, `find_domain_by_name`, `is_domain_created`
- `set_current_domain`, `get_current_domain`

**Planning Strategy Control:**
- `set_recursive_planning`, `get_recursive_planning`, `reset_planning_strategy`
- `set_verbose_level`, `get_verbose_level`

**Iterative Planning Implementation:**
- `seek_plan_iterative` and related iterative planning functions
- `refine_multigoal_and_continue_iterative`, `refine_unigoal_and_continue_iterative`
- `refine_task_and_continue_iterative`, `apply_action_and_continue_iterative`

### Renaming

`_recursive` has been added at the end of the identifiers of the original functions involved in seeking for a plan: 

- seek_plan → `seek_plan_recursive`
- _apply_action_and_continue → `apply_action_and_continue_recursive`
- _refine_multigoal_and_continue → `refine_multigoal_and_continue_recursive`
- _refine_unigoal_and_continue → `refine_unigoal_and_continue_recursive`
- _refine_task_and_continue → `refine_task_and_continue_recursive`


## Version History

### πŸš€ **1.3.0 β€” Thread-Safe Sessions** (Latest, Recommended)
**Uploaded to PyPI: https://pypi.org/project/gtpyhop/1.3.0/**

**Major Features:**
- **πŸ”’ Thread-safe session-based architecture** - Reliable concurrent planning
- **⏱️ Timeout management** - Built-in timeout enforcement and resource management
- **πŸ’Ύ Session persistence** - Save and restore planning sessions
- **πŸ“Š Structured logging** - Programmatic access to planning logs and statistics
- **πŸ”§ Enhanced error handling** - Graceful degradation and comprehensive error reporting
- **πŸ“š Complete example migration** - All 10 examples support both legacy and session modes

**Examples Migration Status:** βœ… **Complete** - All examples now support dual-mode execution:
- 6 simple examples: `simple_htn`, `simple_hgn`, `backtracking_htn`, `simple_htn_acting_error`, `logistics_hgn`, `pyhop_simple_travel_example`
- 4 complex block world examples: `blocks_htn`, `blocks_hgn`, `blocks_gtn`, `blocks_goal_splitting`
- Unified command-line interface: `--session`, `--verbose N`, `--no-pauses`
- Comprehensive test coverage: 9/9 examples pass in both legacy and session modes

**Compatibility:** 100% backward compatible with GTPyhop v1.2.1

**When to use:** New projects, concurrent planning, production systems, web APIs

πŸ“– **[Complete 1.3.0  Thread‑Safe Sessions documentation β†’](https://github.com/PCfVW/GTPyhop/blob/pip/GTPyhop-1.3.0-Thread-Safe-Sessions.md)**

---

### 1.2.1 β€” Cosmetics & Documentation
**Uploaded to PyPI: https://pypi.org/project/gtpyhop/1.2.1/**
- Documentation improvements and bug fixes
- Enhanced README with examples
- Iterative planning strategy refinements

### 1.2.0 β€” Initial PyPI Release
**Uploaded to PyPI: https://pypi.org/project/gtpyhop/**
- First PyPI distribution
- Iterative planning strategy introduction
- Domain management utilities

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "gtpyhop",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3",
    "maintainer_email": null,
    "keywords": "Artificial Intelligence, Automated Planning, HTN, Planning",
    "author": null,
    "author_email": "Eric Jacopin <eric.jacopin@protonmail.com>, Dana Nau <nau@umd.edu>",
    "download_url": "https://files.pythonhosted.org/packages/a7/7e/5afc1a006ebd1b871f0203d02a0cc8706428507b7c4c2942ce200b341440/gtpyhop-1.3.0.tar.gz",
    "platform": null,
    "description": "# GTPyhop version 1.3.0\n\n[![Python Version](https://img.shields.io/badge/python-3%2B-blue.svg)](https://www.python.org/downloads/)\n[![License](https://img.shields.io/badge/license-Clear%20BSD-green.svg)](https://github.com/PCfVW/GTPyhop/blob/pip/LICENSE.txt)\n\nGTPyhop is a task-planning system based on [Pyhop](https://bitbucket.org/dananau/pyhop/src/master/), but generalized to plan for both goals and tasks.\n\n[Dana Nau](https://www.cs.umd.edu/~nau/) is the original author of GTPyhop.\n\n## The pip Branch\n\n[This pip branch](https://github.com/PCfVW/GTPyhop/tree/pip) is forked from [Dana Nau's GTPyhop main branch](https://github.com/dananau/GTPyhop) and refactored for PyPI distribution.\n\nThe file tree structure of [this pip branch](https://github.com/PCfVW/GTPyhop/tree/pip), produced with the help of [_GithubTree](https://github.com/mgks/GitHubTree), is the following:\n\n```\n\ud83d\udcc4 LICENSE.txt\n\ud83d\udcc4 pyproject.toml\n\ud83d\udcc4 README.md\n\ud83d\udcc1 src/\n    \u2514\u2500\u2500 \ud83d\udcc1 gtpyhop/\n        \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n        \u251c\u2500\u2500 \ud83d\udcc1 examples/\n            \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n            \u251c\u2500\u2500 \ud83d\udcc4 backtracking_htn.py\n            \u251c\u2500\u2500 \ud83d\udcc1 blocks_goal_splitting/\n                \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n                \u251c\u2500\u2500 \ud83d\udcc4 actions.py\n                \u251c\u2500\u2500 \ud83d\udcc4 examples.py\n                \u251c\u2500\u2500 \ud83d\udcc4 methods.py\n                \u2514\u2500\u2500 \ud83d\udcc4 README.txt\n            \u251c\u2500\u2500 \ud83d\udcc1 blocks_gtn/\n                \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n                \u251c\u2500\u2500 \ud83d\udcc4 actions.py\n                \u251c\u2500\u2500 \ud83d\udcc4 examples.py\n                \u251c\u2500\u2500 \ud83d\udcc4 methods.py\n                \u2514\u2500\u2500 \ud83d\udcc4 README.txt\n            \u251c\u2500\u2500 \ud83d\udcc1 blocks_hgn/\n                \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n                \u251c\u2500\u2500 \ud83d\udcc4 actions.py\n                \u251c\u2500\u2500 \ud83d\udcc4 examples.py\n                \u2514\u2500\u2500 \ud83d\udcc4 methods.py\n            \u251c\u2500\u2500 \ud83d\udcc1 blocks_htn/\n                \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n                \u251c\u2500\u2500 \ud83d\udcc4 actions.py\n                \u251c\u2500\u2500 \ud83d\udcc4 examples.py\n                \u2514\u2500\u2500 \ud83d\udcc4 methods.py\n            \u251c\u2500\u2500 \ud83d\udcc4 logistics_hgn.py\n            \u251c\u2500\u2500 \ud83d\udcc4 pyhop_simple_travel_example.py\n            \u251c\u2500\u2500 \ud83d\udcc4 regression_tests.py\n            \u251c\u2500\u2500 \ud83d\udcc4 simple_hgn.py\n            \u251c\u2500\u2500 \ud83d\udcc4 simple_htn_acting_error.py\n            \u2514\u2500\u2500 \ud83d\udcc4 simple_htn.py\n        \u251c\u2500\u2500 \ud83d\udcc4 logging_system.py\n        \u251c\u2500\u2500 \ud83d\udcc4 main.py\n        \u2514\u2500\u2500 \ud83d\udcc1 test_harness/\n            \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n            \u2514\u2500\u2500 \ud83d\udcc4 test_harness.py\n```\n\n## Installation from PyPI (Recommended: Version 1.3.0)\n\n**GTPyhop 1.3.0 is the latest version with thread-safe sessions and enhanced reliability.** For new projects, especially those requiring concurrent planning, use 1.3.0:\n\n```bash\npip install gtpyhop>=1.3.0\n```\n\nFor basic single-threaded planning, any version works:\n```bash\npip install gtpyhop\n```\n\n[uv](https://docs.astral.sh/uv/) can of course be used if you prefer:\n\n```bash\nuv pip install gtpyhop\n```\n\n## Installation from github\n\nAlternatively, you can directly install from github:\n\n```bash\ngit clone -b pip https://github.com/PCfVW/GTPyhop.git\ncd GTPyhop\npip install .\n```\n\n## Testing your installation\n\nWe suggest you give gtpyhop a try straight away; open a terminal and start an interactive python session:\n```bash\npython\n```\n\n.. and import gtpyhop to run the regression tests:\n\n```python\n# Import the main GTPyhop planning system\nimport gtpyhop\n```\n\nThe following should be printed in your terminal:\n\n```code\nImported GTPyhop version 1.3.0\nMessages from find_plan will be prefixed with 'FP>'.\nMessages from run_lazy_lookahead will be prefixed with 'RLL>'.\nUsing session-based architecture with structured logging.\n```\n\nNow import the regression tests module:\n\n```python\nfrom gtpyhop.examples import regression_tests\n```\n\nBe prepared to see a lot of information on the screen about the examples and how to solve them, with different levels of verbosity; with this in mind, run the regression tests:\n\n```python\n# Run legacy regression tests (backward compatible)\nregression_tests.main()\n\n# Or run session-based regression tests (recommended for 1.3.0+)\nregression_tests.main_session()\n```\n\nThe last line printed in your terminal should be:\n\n```code\nFinished without error.\n```\n\n**\ud83c\udd95 New in 1.3.0:** You can also run regression tests from the command line:\n\n```bash\n# Legacy mode\npython -m gtpyhop.examples.regression_tests\n\n# Session mode (thread-safe)\npython -m gtpyhop.examples.regression_tests --session\n```\n\nHappy Planning!\n\n## \ud83c\udd95 New in 1.3.0: Thread-Safe Sessions\n\n**GTPyhop 1.3.0 introduces session-based, thread-safe planning** that enables reliable concurrent execution and isolated planning contexts. This is a major architectural enhancement while maintaining 100% backward compatibility.\n\n### Key Benefits\n- **Thread-safe concurrent planning**: Multiple planners can run simultaneously without interference\n- **Isolated execution contexts**: Each session has its own configuration, logs, and statistics\n- **Structured logging system**: Programmatic access to planning traces, statistics, and debugging information\n- **Timeout management**: Built-in timeout enforcement and resource management\n- **Session persistence**: Save and restore planning sessions across runs\n\n### Quick Start with Sessions\n```python\nimport gtpyhop\n\n# Create a Domain and define actions/methods (same as before)\nmy_domain = gtpyhop.Domain('my_domain')\n# ... define actions and methods ...\n\n# NEW: Use session-based planning for thread safety\nwith gtpyhop.PlannerSession(domain=my_domain, verbose=1) as session:\n    with session.isolated_execution():\n        result = session.find_plan(state, [('transport', 'obj1', 'loc2')])\n        if result.success:\n            print(result.plan)\n```\n\n\ud83d\udcd6 **For detailed examples, concurrent planning patterns, and complete API reference, see [GTPyhop-1.3.0-Thread-Safe-Sessions.md](https://github.com/PCfVW/GTPyhop/blob/pip/GTPyhop-1.3.0-Thread-Safe-Sessions.md)**\n\n## Usage\n\nYou have successfully installed and tested gtpyhop; it's time to declare your own planning problems in gtpyhop.\n\n### Very first HTN example\n\nThe key pattern is: create a Domain \u2192 define actions/methods \u2192 declare them \u2192 use gtpyhop.find_plan() to solve problems.\n\nIn the first three steps, we give simple illustrations on Domain creation, action and task method definition, and how to declare them; in step 4 below, you'll find the code for a complete example.\n\n**1. First, create a Domain to hold your definitions**\n\n```python\nimport gtpyhop\n\n# Create a Domain\ngtpyhop.Domain('my_domain')\n```\n\n**2. Define Actions**\n\nActions are atomic operations that directly modify a state: actions are Python functions where the first argument is the current `state`, and the others are the action's arguments telling what changes the action shall bring to the state.\n\nFor example, the function my_action(state, arg1, arg2) below implements the action ('my_action', arg1, arg2). In the following code, `arg1` is used as an object key to check and modify its position, while `arg2` is used both as a condition to check against and as a key to update the status:\n\n```python\ndef my_action(state, arg1, arg2):\n    # Check preconditions using arg1 and arg2\n    if state.pos[arg1] == arg2:\n        # Modify state using arg1 and arg2\n        state.pos[arg1] = 'new_location'\n        state.status[arg2] = 'updated'\n        return state  # Success\n    return False  # Failure\n\n# Declare actions\ngtpyhop.declare_actions(my_action, another_action)\n```\n\n**3. Define Task Methods**\n\nDuring planning, Task methods decompose compound tasks into subtasks (which shall be further decomposed) and actions (whose Python functions will be executed).\n\nTask methods are also Python functions where the first argument is the current `state`, and the others can be passed to the subtasks and actions.\n\nIn the following code, `arg1` is used as an argument to the subtasks (perhaps specifying what object to work with), while `arg2` is used as an argument to the action (perhaps specifying a target location or condition):\n\n```python\ndef method_for_task(state, arg1, arg2):\n    # Check if this method is applicable\n    if some_condition:\n        # Return list of subtasks/actions\n        return [('subtask1', arg1), ('action1', arg2)]\n    return False  # Method not applicable\n\n# Declare task methods\ngtpyhop.declare_task_methods('task_name', method_for_task, alternative_method)\n```\n\n**4. Here is a complete example:**\n\n```python\nimport gtpyhop\n\n# Domain creation\ngtpyhop.Domain('my_domain')\n\n# Define state\nstate = gtpyhop.State('initial_state')\nstate.pos = {'obj1': 'loc1', 'obj2': 'loc2'}\n\n# Actions\ndef move(state, obj, target):\n    if obj in state.pos:\n        state.pos[obj] = target\n        return state\n    return False\n\ngtpyhop.declare_actions(move)\n\n# Task methods\ndef transport(state, obj, destination):\n    current = state.pos[obj]\n    if current != destination:\n        return [('move', obj, destination)]\n    return []\n\ngtpyhop.declare_task_methods('transport', transport)\n\n# Find plan\ngtpyhop.set_verbose_level(1)\nplan = gtpyhop.find_plan(state, [('transport', 'obj1', 'loc2')])\nprint(plan)\n```\n\nPut this code in a file, say `my_very_first_htn_example.py`, and run it from a terminal:\n\n```bash\npython my_very_first_htn_example.py\n```\n\nDoes it run correctly? Increase the verbosity level to 2 or 3 and run it again to see more information about the planning process.\n\n### \ud83c\udd95 Session-Based Version (Recommended for 1.3.0+)\n\nFor better isolation and thread safety, use the session-based approach:\n\n```python\nimport gtpyhop\n\n# Domain creation (same as above)\nmy_domain = gtpyhop.Domain('my_domain')\nstate = gtpyhop.State('initial_state')\nstate.pos = {'obj1': 'loc1', 'obj2': 'loc2'}\n\n# Define actions and methods (same as above)\ndef move(state, obj, target):\n    if obj in state.pos:\n        state.pos[obj] = target\n        return state\n    return False\n\ngtpyhop.declare_actions(move)\n\ndef transport(state, obj, destination):\n    current = state.pos[obj]\n    if current != destination:\n        return [('move', obj, destination)]\n    return []\n\ngtpyhop.declare_task_methods('transport', transport)\n\n# NEW: Use session-based planning\nwith gtpyhop.PlannerSession(domain=my_domain, verbose=1) as session:\n    with session.isolated_execution():\n        result = session.find_plan(state, [('transport', 'obj1', 'loc2')])\n        if result.success:\n            print(\"Plan found:\", result.plan)\n            print(\"Planning stats:\", result.stats)\n\n            # NEW: Access structured logs\n            logs = session.logger.get_logs()\n            print(f\"Generated {len(logs)} log entries during planning\")\n        else:\n            print(\"Planning failed:\", result.error)\n```\n\n**Benefits of the session approach:**\n- Thread-safe for concurrent use\n- Isolated configuration per session\n- Built-in timeout and resource management\n- Structured result objects with statistics\n- **Comprehensive logging system** with programmatic access to planning traces\n- Session persistence capabilities\n\n### \ud83d\udd04 Migration from Pre-1.3.0 Versions\n\n**Existing code continues to work unchanged** - GTPyhop 1.3.0 maintains 100% backward compatibility.\n\n**To leverage 1.3.0 features:**\n1. **For single-threaded code**: No changes required, but consider sessions for better structure\n2. **For concurrent code**: Migrate to `PlannerSession` to avoid race conditions\n3. **For production systems**: Use sessions for timeout management and structured logging\n\n**Simple migration pattern:**\n```python\n# Before (still works)\nplan = gtpyhop.find_plan(state, tasks)\n\n# After (recommended)\nwith gtpyhop.PlannerSession(domain=my_domain) as session:\n    with session.isolated_execution():\n        result = session.find_plan(state, tasks)\n        plan = result.plan if result.success else None\n```\n\n### \ud83d\udccb Version Selection Guide\n\n| Use Case | Recommended Version | Why |\n|----------|-------------------|-----|\n| **New projects** | **1.3.0** | Latest features, thread safety, better error handling |\n| **Concurrent/parallel planning** | **1.3.0** | Thread-safe sessions prevent race conditions |\n| **Production systems** | **1.3.0** | Timeout management, structured logging, persistence |\n| **Web APIs/servers** | **1.3.0** | Isolated sessions per request, timeout handling |\n| **Educational/simple scripts** | Any version | All versions support basic planning |\n| **Legacy code maintenance** | Keep current | All versions are backward compatible |\n\n### Additional Information\n\nPlease read [Dana's additional information](https://github.com/dananau/GTPyhop/blob/main/additional_information.md) of how to implement:\n- [States](https://github.com/dananau/GTPyhop/blob/main/additional_information.md#states)\n- [Actions](https://github.com/dananau/GTPyhop/blob/main/additional_information.md#actions)\n- [Tasks and task methods](https://github.com/dananau/GTPyhop/blob/main/additional_information.md#3-tasks-and-task-methods)\n- [Goals and goal methods](https://github.com/dananau/GTPyhop/blob/main/additional_information.md#4-goals-and-goal-methods)\n- ...and much more about GTPyhop!\n\n## Examples\n\nGTPyhop includes comprehensive examples demonstrating various planning techniques. **All examples support both legacy and session modes** for maximum flexibility and thread safety.\n\n### \ud83d\ude80 Running Examples\n\n**All examples support dual-mode execution:**\n\n```bash\n# Legacy mode (backward compatible)\npython -m gtpyhop.examples.simple_htn\n\n# Session mode (thread-safe, recommended for 1.3.0+)\npython -m gtpyhop.examples.simple_htn --session\n\n# Session mode with custom verbosity and no pauses\npython -m gtpyhop.examples.simple_htn --session --verbose 2 --no-pauses\n```\n\n**Command-line arguments (available in all migrated examples):**\n- `--session`: Enable thread-safe session mode\n- `--verbose N`: Set verbosity level (0-3, default: 1 in session mode)\n- `--no-pauses`: Skip interactive pauses for automated testing\n\n### \ud83d\udccb Available Examples\n\n#### **Simple Examples** (Basic concepts and techniques)\n\n| Example | Description | Key Features |\n|---------|-------------|--------------|\n| `simple_htn.py` | Basic hierarchical task networks | HTN planning, verbosity levels, execution |\n| `simple_hgn.py` | Basic hierarchical goal networks | HGN planning, goal-oriented tasks |\n| `backtracking_htn.py` | Backtracking demonstration | Method failure handling, alternative paths |\n| `simple_htn_acting_error.py` | Error handling patterns | Execution failures, replanning |\n| `logistics_hgn.py` | Logistics domain planning | Multi-goal planning, transportation |\n| `pyhop_simple_travel_example.py` | Travel planning | Basic domain modeling |\n\n#### **Complex Block World Examples** (Advanced planning scenarios)\n\n| Example | Description | Key Features |\n|---------|-------------|--------------|\n| `blocks_htn/` | Hierarchical task networks | Complex HTN methods, block manipulation |\n| `blocks_hgn/` | Hierarchical goal networks | Goal decomposition, multigoals |\n| `blocks_gtn/` | Goal task networks | Mixed task/goal planning |\n| `blocks_goal_splitting/` | Goal splitting methodology | Built-in goal decomposition methods |\n\n### \ud83e\uddea Testing Examples\n\n**Run all examples automatically:**\n\n```bash\n# Test all examples in both modes\npython test_migration.py\n\n# Test only session mode\npython test_migration.py --mode session\n\n# Test only legacy mode\npython test_migration.py --mode legacy\n```\n\n**Run regression tests:**\n\n```bash\n# Legacy regression tests\npython -m gtpyhop.examples.regression_tests\n\n# Session-based regression tests\npython -m gtpyhop.examples.regression_tests --session\n```\n\n### \ud83d\udca1 Example Usage Patterns\n\n**Interactive exploration:**\n```bash\n# Run with pauses to examine output step by step\npython -m gtpyhop.examples.blocks_htn.examples --session --verbose 3\n```\n\n**Automated testing:**\n```bash\n# Run without pauses for scripts/CI\npython -m gtpyhop.examples.blocks_htn.examples --session --no-pauses\n```\n\n**Concurrent planning (session mode only):**\n```python\nimport threading\nimport gtpyhop\n\n# Load example Domain\nfrom gtpyhop.examples.blocks_htn import actions, methods\n\ndef plan_worker(session_id, state, goals):\n    with gtpyhop.PlannerSession(domain=the_domain, verbose=1) as session:\n        with session.isolated_execution():\n            result = session.find_plan(state, goals)\n            print(f\"Session {session_id}: {result.plan}\")\n\n# Run multiple planners concurrently\nthreads = []\nfor i in range(3):\n    t = threading.Thread(target=plan_worker, args=(i, initial_state, goals))\n    threads.append(t)\n    t.start()\n\nfor t in threads:\n    t.join()\n```\n\n## Structured Logging System\n\nGTPyhop 1.3.0 introduces a comprehensive structured logging system that replaces traditional print statements with configurable, thread-safe logging. This system provides programmatic access to planning logs, statistics, and debugging information.\n\n### \ud83c\udfaf Why Structured Logging?\n\n**Traditional challenges:**\n- Print statements mixed with actual output\n- No programmatic access to planning information\n- Difficult to filter or analyze planning traces\n- Thread safety issues in concurrent scenarios\n\n**Structured logging benefits:**\n- **Programmatic access**: Query and analyze logs programmatically\n- **Thread isolation**: Each session maintains separate logs\n- **Configurable output**: Control verbosity and formatting\n- **Performance monitoring**: Built-in statistics and performance metrics\n- **Backward compatibility**: Existing print-based output still works\n\n### \ud83d\udd27 How It Works\n\nThe logging system operates in both legacy and session modes:\n\n**Legacy Mode:** Uses global logging with backward-compatible print output\n**Session Mode:** Each `PlannerSession` has isolated logging with structured data collection\n\n### \ud83d\udcca Log Levels and Components\n\n**Available log levels:**\n- `DEBUG` (0): Detailed debugging information\n- `INFO` (1): General planning information\n- `WARNING` (2): Warning messages\n- `ERROR` (3): Error conditions\n\n**Common components:**\n- `FP`: Messages from `find_plan()`\n- `RLL`: Messages from `run_lazy_lookahead()`\n- `domain`: Domain-related operations\n- `session`: Session management\n- `stdout_capture`: Captured print statements\n\n### \ud83d\udcbb Basic Usage Examples\n\n**Import note:** All logging classes and functions are available directly from the main `gtpyhop` module:\n\n```python\nimport gtpyhop\n\n# Logging classes are available as gtpyhop.LogLevel, gtpyhop.StructuredLogger, etc.\n# Or import specific components:\nfrom gtpyhop import LogLevel, StructuredLogger, get_logging_stats\n```\n\n#### **Session Mode Logging (Recommended)**\n\n```python\nimport gtpyhop\n\n# Create session with logging\nwith gtpyhop.PlannerSession(domain=my_domain, verbose=2) as session:\n    with session.isolated_execution():\n        result = session.find_plan(state, goals)\n\n        # Access structured logs\n        logs = session.logger.get_logs()  # Get all INFO+ logs\n        debug_logs = session.logger.get_logs(min_level=gtpyhop.LogLevel.DEBUG)\n\n        # Print log summary\n        print(f\"Generated {len(logs)} log entries\")\n        for log in logs:\n            print(f\"[{log['level']}] {log['component']}: {log['message']}\")\n```\n\n#### **Custom Log Handlers**\n\n```python\nimport gtpyhop\n\n# Create custom logger\nlogger = gtpyhop.StructuredLogger(\"my_session\")\n\n# Add custom stdout handler with formatting\ncustom_handler = gtpyhop.StdoutLogHandler(\"[{level}] {component}: {message}\")\nlogger.add_handler(custom_handler)\n\n# Log custom messages\nlogger.info(\"planning\", \"Starting plan search\", state_size=len(state.pos))\nlogger.debug(\"search\", \"Exploring method\", method_name=\"transport_by_truck\")\n```\n\n#### **Programmatic Log Analysis**\n\n```python\n# Run planning with logging\nwith gtpyhop.PlannerSession(domain=logistics_domain, verbose=3) as session:\n    with session.isolated_execution():\n        result = session.find_plan(initial_state, goals)\n\n        # Analyze logs\n        logs = session.logger.get_logs()\n\n        # Count log entries by component\n        component_counts = {}\n        for log in logs:\n            component = log['component']\n            component_counts[component] = component_counts.get(component, 0) + 1\n\n        print(\"Log summary by component:\")\n        for component, count in component_counts.items():\n            print(f\"  {component}: {count} entries\")\n\n        # Find error logs\n        error_logs = [log for log in logs if log['level'] == 'ERROR']\n        if error_logs:\n            print(f\"Found {len(error_logs)} errors:\")\n            for error in error_logs:\n                print(f\"  {error['message']}\")\n```\n\n### \ud83e\uddf5 Thread-Safe Concurrent Logging\n\nEach session maintains isolated logs, making concurrent planning safe:\n\n```python\nimport threading\nimport gtpyhop\n\ndef concurrent_planner(session_id, domain, state, goals):\n    \"\"\"Each thread gets isolated logging.\"\"\"\n    with gtpyhop.PlannerSession(domain=domain, verbose=2) as session:\n        with session.isolated_execution():\n            result = session.find_plan(state, goals)\n\n            # Each session has separate logs\n            logs = session.logger.get_logs()\n            print(f\"Session {session_id}: {len(logs)} log entries\")\n\n            return result, logs\n\n# Run multiple planners concurrently\nthreads = []\nresults = {}\n\nfor i in range(3):\n    def worker(session_id=i):\n        result, logs = concurrent_planner(session_id, domain, state, goals)\n        results[session_id] = {\"result\": result, \"logs\": logs}\n\n    t = threading.Thread(target=worker)\n    threads.append(t)\n    t.start()\n\nfor t in threads:\n    t.join()\n\n# Analyze results from each session\nfor session_id, data in results.items():\n    print(f\"Session {session_id}: {len(data['logs'])} logs, \"\n          f\"plan length: {len(data['result'].plan) if data['result'].success else 'failed'}\")\n```\n\n### \ud83d\udcc8 Performance Monitoring\n\nThe logging system includes built-in performance monitoring:\n\n```python\nimport gtpyhop\n\nwith gtpyhop.PlannerSession(domain=my_domain, verbose=2) as session:\n    with session.isolated_execution():\n        result = session.find_plan(state, goals)\n\n        # Get logging statistics\n        stats = gtpyhop.get_logging_stats(session.logger)\n\n        print(f\"Logging Performance:\")\n        print(f\"  Total entries: {stats.total_entries}\")\n        print(f\"  Memory usage: {stats.memory_usage_mb:.2f} MB\")\n        print(f\"  Entries by level: {stats.entries_by_level}\")\n```\n\n### \ud83d\udd04 Legacy Mode Compatibility\n\nThe logging system maintains backward compatibility with existing code:\n\n```python\n# Legacy code continues to work\ngtpyhop.verbose = 2\nplan = gtpyhop.find_plan(state, goals)  # Prints to stdout as before\n\n# But you can also access logs programmatically\nlogger = gtpyhop.get_logger(\"default\")  # Get default session logger\nlogs = logger.get_logs()\nprint(f\"Legacy planning generated {len(logs)} log entries\")\n```\n\n### \ud83d\udee0\ufe0f Advanced Features\n\n#### **Stdout Capture**\n\nCapture and log print statements from legacy code:\n\n```python\nlogger = gtpyhop.StructuredLogger(\"capture_session\")\n\nwith logger.capture_stdout() as captured:\n    # Any print statements here are captured and logged\n    print(\"This will be captured\")\n    gtpyhop.find_plan(state, goals)  # Legacy prints captured\n\n# Captured output is now in structured logs\nlogs = logger.get_logs()\nstdout_logs = [log for log in logs if log['component'] == 'stdout_capture']\n```\n\n#### **Custom Log Filtering**\n\n```python\n# Filter logs by component and level\ndef filter_planning_logs(logs, component_filter=None, min_level='INFO'):\n    filtered = []\n    for log in logs:\n        if component_filter and log['component'] != component_filter:\n            continue\n        if log['level'] not in ['DEBUG', 'INFO', 'WARNING', 'ERROR'][\n            ['DEBUG', 'INFO', 'WARNING', 'ERROR'].index(min_level):]:\n            continue\n        filtered.append(log)\n    return filtered\n\n# Usage\nplanning_logs = filter_planning_logs(logs, component_filter='FP', min_level='INFO')\n```\n\n### \ud83c\udf93 Integration with Examples\n\nAll migrated examples support structured logging in session mode:\n\n```bash\n# Run with high verbosity to see detailed logs\npython -m gtpyhop.examples.blocks_htn.examples --session --verbose 3\n\n# The logs are available programmatically when using session mode\n```\n\n**Example integration in your code:**\n\n```python\n# Import any migrated example domain\nfrom gtpyhop.examples.blocks_htn import the_domain, actions, methods\n\n# Use with structured logging\nwith gtpyhop.PlannerSession(domain=the_domain, verbose=2) as session:\n    with session.isolated_execution():\n        result = session.find_plan(initial_state, goals)\n\n        # Access detailed planning logs\n        logs = session.logger.get_logs()\n        method_calls = [log for log in logs if 'method' in log.get('context', {})]\n        print(f\"Called {len(method_calls)} methods during planning\")\n```\n\n### \ud83d\udcda Documentation Structure\n\n- **README.md** (this file): Installation, basic usage, and overview of all features\n- **[GTPyhop-1.3.0-Thread-Safe-Sessions.md](https://github.com/PCfVW/GTPyhop/tree/pipGTPyhop-1.3.0-Thread-Safe-Sessions.md)**: Comprehensive guide to 1.3.0 session-based architecture\n  - Detailed concurrent planning examples\n  - Complete API reference for session management\n  - Migration guide from global API to sessions\n  - Performance considerations and best practices\n- **[Dana's additional information](https://github.com/dananau/GTPyhop/blob/main/additional_information.md)**: Core GTPyhop concepts (states, actions, goals, methods)\n\n## New Features\n\n### Iterative Planning Strategy\n\n[This pip branch](https://github.com/PCfVW/GTPyhop/tree/pip) introduces a new iterative planning strategy that enhances the planner's capabilities for large planning scenarios; it is the default strategy.\n\n- How it works: Uses an explicit stack data structure\n- Memory usage: More memory-efficient, no call stack buildup\n- Limitations: No recursion limit constraints\n- Backtracking: Explicit stack management for exploring alternatives\n- Use cases:\n    - Large planning problems that might exceed recursion limits\n    - Memory-constrained environments\n    - Production systems requiring reliability\n\nOnce gtpyhop is imported, Dana Nau's original recursive strategy can be set by calling:\n\n```python\nset_recursive_planning(True)  # Planning strategy now is recursive\n```\n\nRecursive Planning Strategy:\n- How it works: Uses Python's call stack with recursive function calls\n- Memory usage: Each recursive call adds a frame to the call stack\n- Limitations: Limited by Python's recursion limit (default 1000)\n- Backtracking: Natural backtracking through function returns\n- Use cases:\n    - Small to medium planning problems\n    - When you need to see traditional backtracking behavior\n    - Educational purposes or debugging\n\nOf course you can get back to the iterative planning strategy by calling:\n\n```python\nset_recursive_planning(False)  # Planning strategy now is iterative\n```\n\n### New Functions\n\n#### Functions Added in 1.3.0 (Thread-Safe Sessions)\n**Session Management:**\n- `PlannerSession` (class) - Isolated, thread-safe planning context\n- `create_session`, `get_session`, `destroy_session`, `list_sessions` - Session lifecycle management\n- `PlanningTimeoutError` (exception) - Timeout handling for session-scoped operations\n\n**Session Persistence:**\n- `SessionSerializer` (class), `restore_session`, `restore_all_sessions` - Session persistence and recovery\n- `set_persistence_directory`, `get_persistence_directory` - Configure auto-save/recovery\n\n**Enhanced Planning:**\n- `session.find_plan()` - Per-session planning with timeout and expansion limits\n- `session.isolated_execution()` - Context manager for safe global state management\n\n#### Functions Added in 1.2.1 (Iterative Planning & Utilities)\n**Domain Management:**\n- `print_domain_names`, `find_domain_by_name`, `is_domain_created`\n- `set_current_domain`, `get_current_domain`\n\n**Planning Strategy Control:**\n- `set_recursive_planning`, `get_recursive_planning`, `reset_planning_strategy`\n- `set_verbose_level`, `get_verbose_level`\n\n**Iterative Planning Implementation:**\n- `seek_plan_iterative` and related iterative planning functions\n- `refine_multigoal_and_continue_iterative`, `refine_unigoal_and_continue_iterative`\n- `refine_task_and_continue_iterative`, `apply_action_and_continue_iterative`\n\n### Renaming\n\n`_recursive` has been added at the end of the identifiers of the original functions involved in seeking for a plan: \n\n- seek_plan &rarr; `seek_plan_recursive`\n- _apply_action_and_continue &rarr; `apply_action_and_continue_recursive`\n- _refine_multigoal_and_continue &rarr; `refine_multigoal_and_continue_recursive`\n- _refine_unigoal_and_continue &rarr; `refine_unigoal_and_continue_recursive`\n- _refine_task_and_continue &rarr; `refine_task_and_continue_recursive`\n\n\n## Version History\n\n### \ud83d\ude80 **1.3.0 \u2014 Thread-Safe Sessions** (Latest, Recommended)\n**Uploaded to PyPI: https://pypi.org/project/gtpyhop/1.3.0/**\n\n**Major Features:**\n- **\ud83d\udd12 Thread-safe session-based architecture** - Reliable concurrent planning\n- **\u23f1\ufe0f Timeout management** - Built-in timeout enforcement and resource management\n- **\ud83d\udcbe Session persistence** - Save and restore planning sessions\n- **\ud83d\udcca Structured logging** - Programmatic access to planning logs and statistics\n- **\ud83d\udd27 Enhanced error handling** - Graceful degradation and comprehensive error reporting\n- **\ud83d\udcda Complete example migration** - All 10 examples support both legacy and session modes\n\n**Examples Migration Status:** \u2705 **Complete** - All examples now support dual-mode execution:\n- 6 simple examples: `simple_htn`, `simple_hgn`, `backtracking_htn`, `simple_htn_acting_error`, `logistics_hgn`, `pyhop_simple_travel_example`\n- 4 complex block world examples: `blocks_htn`, `blocks_hgn`, `blocks_gtn`, `blocks_goal_splitting`\n- Unified command-line interface: `--session`, `--verbose N`, `--no-pauses`\n- Comprehensive test coverage: 9/9 examples pass in both legacy and session modes\n\n**Compatibility:** 100% backward compatible with GTPyhop v1.2.1\n\n**When to use:** New projects, concurrent planning, production systems, web APIs\n\n\ud83d\udcd6 **[Complete 1.3.0  Thread\u2011Safe Sessions documentation \u2192](https://github.com/PCfVW/GTPyhop/blob/pip/GTPyhop-1.3.0-Thread-Safe-Sessions.md)**\n\n---\n\n### 1.2.1 \u2014 Cosmetics & Documentation\n**Uploaded to PyPI: https://pypi.org/project/gtpyhop/1.2.1/**\n- Documentation improvements and bug fixes\n- Enhanced README with examples\n- Iterative planning strategy refinements\n\n### 1.2.0 \u2014 Initial PyPI Release\n**Uploaded to PyPI: https://pypi.org/project/gtpyhop/**\n- First PyPI distribution\n- Iterative planning strategy introduction\n- Domain management utilities\n",
    "bugtrack_url": null,
    "license": "Clear BSD License",
    "summary": "A Goal-Task-Network planning package written in Python",
    "version": "1.3.0",
    "project_urls": {
        "Documentation": "https://github.com/dananau/GTPyhop/blob/main/additional_information.md",
        "Homepage": "https://github.com/PCfVW/GTPyhop/tree/pip",
        "Issues": "https://github.com/PCfVW/GTPyhop/issues",
        "Repository": "https://github.com/PCfVW/GTPyhop.git"
    },
    "split_keywords": [
        "artificial intelligence",
        " automated planning",
        " htn",
        " planning"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "667e9e042f412f39ee085ba961f66fae248015e2551a1980a3c1e91d32207764",
                "md5": "3c85be2da37d8fe1afa1060fecf46057",
                "sha256": "b4486aead8f570851d77f0e2f5f11b4ec81b4d4f96ef9012e5877e5bdd8cdb0a"
            },
            "downloads": -1,
            "filename": "gtpyhop-1.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3c85be2da37d8fe1afa1060fecf46057",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3",
            "size": 85198,
            "upload_time": "2025-08-22T16:41:58",
            "upload_time_iso_8601": "2025-08-22T16:41:58.930411Z",
            "url": "https://files.pythonhosted.org/packages/66/7e/9e042f412f39ee085ba961f66fae248015e2551a1980a3c1e91d32207764/gtpyhop-1.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a77e5afc1a006ebd1b871f0203d02a0cc8706428507b7c4c2942ce200b341440",
                "md5": "999520bea3e170bce483c41a7eee9906",
                "sha256": "30539939a4e717bfe77a96888c17acfd6791751f25859ba53837e3e1e1ca4fdd"
            },
            "downloads": -1,
            "filename": "gtpyhop-1.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "999520bea3e170bce483c41a7eee9906",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3",
            "size": 67105,
            "upload_time": "2025-08-22T16:42:00",
            "upload_time_iso_8601": "2025-08-22T16:42:00.229160Z",
            "url": "https://files.pythonhosted.org/packages/a7/7e/5afc1a006ebd1b871f0203d02a0cc8706428507b7c4c2942ce200b341440/gtpyhop-1.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-22 16:42:00",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "dananau",
    "github_project": "GTPyhop",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "gtpyhop"
}
        
Elapsed time: 0.95639s