Metadata-Version: 2.4
Name: codibox
Version: 1.0.3
Summary: A reusable package for executing Python code in Docker containers and extracting charts/images
Home-page: https://github.com/otmane-elbourki/codibox
Author: Otmane El Bourki
Author-email: otmane.elbourki@gmail.com
Project-URL: Bug Reports, https://github.com/otmane-elbourki/codibox/issues
Project-URL: Source, https://github.com/otmane-elbourki/codibox
Project-URL: Documentation, https://github.com/otmane-elbourki/codibox#readme
Keywords: docker,code-execution,sandbox,jupyter,notebook,matplotlib,charts,images,python-execution
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: System :: Systems Administration
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license-file
Dynamic: project-url
Dynamic: provides-extra
Dynamic: requires-python
Dynamic: summary

# Codibox - Safe Code Execution Package

[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A reusable Python package for executing Python code in Docker containers or on the host machine, with automatic chart/image extraction and result processing.

## 🎯 Features

- **Dual Backend Support**: Choose between Docker (secure, isolated) or Host (fast, direct execution)
- **Automatic Image Extraction**: Automatically finds and extracts charts/images from code execution
- **Markdown Processing**: Converts notebook output to markdown with embedded images
- **CSV File Extraction**: Automatically extracts generated CSV/Excel files
- **Dependency Management**: Auto-installs required packages for host mode
- **Error Handling**: Comprehensive error handling with fallbacks
- **Backward Compatible**: `DockerCodeExecutor` alias maintained for existing code

## 📦 Installation

### From PyPI (Recommended)

```bash
pip install codibox
```

### From Source

```bash
# Clone the repository
git clone https://github.com/otmane-elbourki/codibox.git
cd codibox

# Install in editable mode
pip install -e .
```

### Development Installation

```bash
pip install -e ".[dev]"
```

## 🚀 Quick Start

### Docker Backend (Default - Secure)

```python
from codibox import CodeExecutor

# Initialize executor with Docker backend
executor = CodeExecutor(backend="docker", container_name="sandbox")

# Execute code
result = executor.execute(
    code="""
    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.linspace(0, 10, 100)
    y = np.sin(x)
    
    plt.figure(figsize=(10, 6))
    plt.plot(x, y, label='sin(x)')
    plt.title('Sine Wave')
    plt.savefig('temp_code_files/chart.png')
    plt.close()
    """
)

# Check results
if result.success:
    print(f"✅ Success! Generated {len(result.images)} images")
    for img in result.images:
        print(f"  📊 {img}")
    print(f"📄 Markdown: {result.markdown[:100]}...")
else:
    print(f"❌ Failed: {result.stderr}")
```

### Host Backend (Fast - Direct Execution)

```python
from codibox import CodeExecutor

# Initialize executor with Host backend (fast mode)
executor = CodeExecutor(backend="host", auto_install_deps=True)

# Execute code (same API as Docker backend)
result = executor.execute(
    code="""
    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.linspace(0, 10, 100)
    y = np.cos(x)
    
    plt.figure(figsize=(10, 6))
    plt.plot(x, y)
    plt.title('Cosine Wave')
    plt.savefig('temp_code_files/cosine.png')
    plt.close()
    """
)

# Results work the same way
print(f"Images: {result.images}")
print(f"Success: {result.success}")
```

### Backward Compatibility

```python
# Old code still works!
from codibox import DockerCodeExecutor

executor = DockerCodeExecutor(container_name="sandbox")
result = executor.execute(code="...")
```

## 📋 API Reference

### `CodeExecutor`

Main class for executing Python code with dual backend support.

#### Initialization

```python
CodeExecutor(
    backend: str = "docker",              # "docker" or "host"
    container_name: str = "sandbox",      # Docker container name (docker only)
    host_temp_dir: str = "/tmp",          # Temporary directory on host
    image_output_dir: str = "temp_code_files",  # Directory for images
    timeout: Optional[int] = 300,        # Execution timeout (seconds)
    cleanup_on_error: bool = True,       # Cleanup on error
    auto_setup: bool = False,             # Auto-setup Docker container (docker only)
    auto_install_deps: bool = True,       # Auto-install dependencies (host only)
)
```

#### Methods

##### `execute(code, input_files=None, working_dir=None) -> ExecutionResult`

Execute Python code and return results.

**Parameters:**
- `code` (str): Python code to execute
- `input_files` (List[str], optional): Input files to copy to container/host
- `working_dir` (str, optional): Working directory (default: `/home/sandboxuser` for Docker, temp dir for Host)

**Returns:** `ExecutionResult` object

##### `check_container() -> bool`

Check if Docker container is running (Docker backend only).

##### `get_container_status() -> Dict[str, Any]`

Get detailed status of Docker container (Docker backend only).

**Returns:** Dictionary with `exists`, `running`, `status`, `image`

##### `setup_container(image_name="python_sandbox:latest", force_rebuild=False) -> bool`

Set up Docker container by building image and starting container (Docker backend only).

### `ExecutionResult`

Result object returned by `execute()` method.

```python
@dataclass
class ExecutionResult:
    # Raw outputs
    markdown: str                    # Raw markdown from notebook execution
    success: bool                    # Whether execution succeeded
    images: List[str]                # List of image file paths on host
    csv_files: List[str]             # List of generated CSV/Excel files
    stdout: Optional[str]            # Standard output
    stderr: Optional[str]            # Standard error
    execution_time: Optional[float]  # Execution time in seconds
    
    # Processed outputs
    markdown_processed: Optional[str]      # Markdown with resolved image paths
    markdown_with_images: Optional[str]    # Markdown with base64-embedded images
    image_map: Optional[Dict[str, str]]    # Mapping: markdown_ref -> actual_path
```

### `ImageProcessor`

Utility class for processing images from execution results.

```python
from codibox import ImageProcessor

processor = ImageProcessor(image_base_dir="/tmp/temp_code_files")

# Find all images
images = processor.find_images()

# Process markdown to embed images
processed_markdown = processor.process_markdown(result.markdown)

# Get HTML for all images
html = processor.get_all_images_html()
```

## 🔧 Configuration Examples

### Docker Backend Setup

```python
from codibox import CodeExecutor

# Basic setup
executor = CodeExecutor(backend="docker", container_name="sandbox")

# Auto-setup container if not running
executor = CodeExecutor(
    backend="docker",
    container_name="sandbox",
    auto_setup=True  # Automatically builds/starts container
)

# Manual container setup
executor = CodeExecutor(backend="docker")
if not executor.check_container():
    executor.setup_container()

# Custom timeout
executor = CodeExecutor(backend="docker", timeout=600)  # 10 minutes
```

### Host Backend Setup

```python
from codibox import CodeExecutor

# Basic setup (auto-installs dependencies)
executor = CodeExecutor(backend="host")

# Disable auto-installation
executor = CodeExecutor(
    backend="host",
    auto_install_deps=False  # You must install dependencies manually
)

# Custom temp directory
executor = CodeExecutor(
    backend="host",
    host_temp_dir="/custom/tmp"
)
```

## 📊 Usage Examples

### With Input Files

```python
executor = CodeExecutor(backend="docker")

result = executor.execute(
    code="""
    import pandas as pd
    import matplotlib.pyplot as plt
    
    df = pd.read_csv('data.csv')
    plt.hist(df['age'], bins=20, edgecolor='black')
    plt.title('Age Distribution')
    plt.savefig('temp_code_files/age_dist.png')
    plt.close()
    """,
    input_files=["datasets/customer_data.csv"]
)

print(f"Generated {len(result.images)} charts")
print(f"CSV files: {result.csv_files}")
```

### Processing Images

```python
from codibox import CodeExecutor, ImageProcessor

executor = CodeExecutor(backend="host")
result = executor.execute(code="...")

# Process images
processor = ImageProcessor()
markdown_with_images = processor.process_markdown(result.markdown)

# Or get all images as HTML
images_html = processor.get_all_images_html()
print(images_html)
```

### Accessing Processed Results

```python
result = executor.execute(code="...")

# Raw markdown (with image references)
print(result.markdown)

# Processed markdown (with resolved paths)
if result.markdown_processed:
    print(result.markdown_processed)

# Markdown with embedded base64 images
if result.markdown_with_images:
    print(result.markdown_with_images)

# Image mapping
if result.image_map:
    for ref, path in result.image_map.items():
        print(f"{ref} -> {path}")
```

## 🐳 Docker Backend Details

### Container Setup

The Docker backend requires a running container. You can:

1. **Auto-setup** (recommended for development):
   ```python
   executor = CodeExecutor(backend="docker", auto_setup=True)
   ```

2. **Manual setup**:
   ```python
   executor = CodeExecutor(backend="docker")
   executor.setup_container()
   ```

3. **Use existing container**:
   ```python
   executor = CodeExecutor(backend="docker", container_name="my_container")
   ```

### Container Requirements

The container should have:
- Python 3.10+
- Required packages: `pandas`, `numpy`, `matplotlib`, `jupyter`, `nbconvert`, `ipynb-py-convert`
- Working directory: `/home/sandboxuser` (or `/tmp`)

The package includes a `Dockerfile` and `requirements.txt` in the `docker/` directory for building a compatible container.

## 💻 Host Backend Details

### Automatic Dependency Management

The Host backend automatically checks and installs required packages:
- `matplotlib`
- `pandas`
- `numpy`
- `jupyter`
- `nbconvert`
- `ipynb-py-convert`

### Python 3.13 Compatibility

The Host backend automatically handles Python 3.13 SQLite issues by falling back to direct Python execution when Jupyter fails.

### Security Considerations

⚠️ **Important**: The Host backend runs code with user permissions and has no isolation. Use Docker backend for untrusted code.

## 🔄 Backend Comparison

| Feature | Docker Backend | Host Backend |
|---------|---------------|--------------|
| **Security** | ✅ Isolated, secure | ⚠️ Runs with user permissions |
| **Speed** | ~2-5 seconds | ~0.5-2 seconds |
| **Setup** | Requires Docker | No setup needed |
| **Dependencies** | Pre-installed in container | Auto-installed on first use |
| **Isolation** | ✅ Full isolation | ❌ No isolation |
| **Network** | ❌ No network access | ✅ Full network access |
| **Use Case** | Production, untrusted code | Development, trusted code |

## 📝 Examples

See the `examples/` directory for complete usage examples:

- **`basic_usage.py`** - Simple code execution examples
- **`ai_analyst/`** - Complete Streamlit dashboard application
- **`README.md`** - Detailed examples documentation

### Running Examples

```bash
# Setup Docker container (if using Docker backend)
cd examples
./setup_example.sh

# Run basic examples
python basic_usage.py

# Run Streamlit app
cd ai_analyst
streamlit run streamlit_chart_generator.py
```

## 🧪 Testing

Run the test suite to verify both backends:

```bash
python3 test/test_both_backends.py
```

This will test:
- Docker backend execution
- Host backend execution
- Image generation and extraction
- Markdown processing
- Error handling

## 📚 Advanced Usage

### Custom Working Directory

```python
# Docker backend
result = executor.execute(
    code="...",
    working_dir="/custom/path"
)

# Host backend
executor = CodeExecutor(
    backend="host",
    host_temp_dir="/custom/tmp"
)
```

### Error Handling

```python
result = executor.execute(code="...")

if not result.success:
    print(f"Execution failed: {result.stderr}")
    print(f"Execution time: {result.execution_time}s")
else:
    print(f"Success! Generated {len(result.images)} images")
```

### Container Management

```python
executor = CodeExecutor(backend="docker")

# Check container status
status = executor.get_container_status()
print(f"Container exists: {status['exists']}")
print(f"Container running: {status['running']}")

# Setup container
if not executor.check_container():
    executor.setup_container(force_rebuild=True)
```

## 🔍 Troubleshooting

### Docker Backend Issues

**Container not found:**
```python
# Auto-setup container
executor = CodeExecutor(backend="docker", auto_setup=True)

# Or manually setup
executor.setup_container()
```

**Images not extracted:**
- Ensure code saves images to `temp_code_files/` directory
- Check container working directory matches executor configuration

### Host Backend Issues

**Dependencies not installed:**
```python
# Enable auto-installation
executor = CodeExecutor(backend="host", auto_install_deps=True)
```

**Python 3.13 SQLite errors:**
- Automatically handled with fallback to direct Python execution
- No action needed

**Images not found:**
- Ensure `temp_code_files/` directory exists (created automatically)
- Check image paths in code match `image_output_dir` setting

## 📦 Package Structure

```
codibox/
├── __init__.py              # Package initialization
├── executor.py              # CodeExecutor class
├── image_processor.py       # Image processing utilities
├── types.py                 # Type definitions
├── docker/
│   ├── Dockerfile          # Docker image definition
│   └── requirements.txt    # Docker dependencies
├── test/
│   └── test_both_backends.py  # Test script
└── examples/               # Usage examples
```

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 👤 Author

**Otmane El Bourki**
- Email: otmane.elbourki@gmail.com
- GitHub: [@otmane-elbourki](https://github.com/otmane-elbourki)

## 🔗 Links

- **PyPI**: https://pypi.org/project/codibox/
- **GitHub**: https://github.com/otmane-elbourki/codibox
- **Issues**: https://github.com/otmane-elbourki/codibox/issues

---

**Version:** 1.0.3
