Metadata-Version: 2.4
Name: podstack
Version: 1.2.0
Summary: Official Python SDK for Podstack GPU Notebook Platform
Author-email: Podstack <support@podstack.io>
License-Expression: MIT
Project-URL: Homepage, https://podstack.io
Project-URL: Documentation, https://docs.podstack.io
Project-URL: Repository, https://github.com/podstack/podstack-python
Project-URL: Issues, https://github.com/podstack/podstack-python/issues
Keywords: gpu,notebook,machine-learning,deep-learning,cloud,jupyter
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.24.0
Requires-Dist: requests>=2.28.0
Provides-Extra: torch
Requires-Dist: torch; extra == "torch"
Provides-Extra: tensorflow
Requires-Dist: tensorflow; extra == "tensorflow"
Provides-Extra: sklearn
Requires-Dist: scikit-learn; extra == "sklearn"
Provides-Extra: huggingface
Requires-Dist: transformers; extra == "huggingface"
Requires-Dist: safetensors; extra == "huggingface"
Provides-Extra: all
Requires-Dist: torch; extra == "all"
Requires-Dist: tensorflow; extra == "all"
Requires-Dist: scikit-learn; extra == "all"
Requires-Dist: transformers; extra == "all"
Requires-Dist: safetensors; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: ruff>=0.0.270; extra == "dev"
Dynamic: license-file

# Podstack Python SDK

Official Python SDK for the Podstack GPU Notebook Platform. Launch GPU notebooks in under 1 second and execute ML workloads with ease.

## Installation

```bash
pip install podstack
```

## Quick Start

```python
import asyncio
from podstack import Client

async def main():
    async with Client(api_key="your-api-key") as client:
        # Create a GPU notebook
        notebook = await client.notebooks.create(
            name="my-experiment",
            gpu_type="A100",
            environment="pytorch"
        )

        # Execute code
        result = await notebook.execute("""
import torch
print(f"GPU: {torch.cuda.get_device_name(0)}")
print(f"Memory: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB")
        """)

        print(result.output)

        # Save a version
        version = await notebook.save(message="Initial experiment")

        # Stop when done
        await notebook.stop()

asyncio.run(main())
```

## Sync Usage

For simple scripts, use the sync wrappers:

```python
from podstack import Client

client = Client(api_key="your-api-key")

# Create notebook
notebook = client.sync_create_notebook(name="quick-test", gpu_type="A10")

# Run code
result = client.sync_run("print('Hello GPU!')", gpu_type="A10")
print(result.output)
```

## Features

### Notebooks

```python
# Create with options
notebook = await client.notebooks.create(
    name="training-run",
    gpu_type="A100",
    environment="pytorch",
    project_id="proj_xxx",
    idle_timeout_minutes=60,
    auto_shutdown_enabled=True,
    metadata={"experiment": "v2"}
)

# List notebooks
notebooks = await client.notebooks.list(status="running")

# Execute code
result = await notebook.execute("import torch; print(torch.cuda.device_count())")

# Access JupyterLab
print(f"JupyterLab: {notebook.jupyter_url}")

# Stop/Start
await notebook.stop()
await notebook.start()
```

### Serverless Executions

Run code without managing notebooks:

```python
# Quick execution
result = await client.executions.run(
    code="print('Hello!')",
    gpu_type="A10",
    environment="pytorch"
)

# Non-blocking execution
execution = await client.executions.create(
    code=long_running_code,
    gpu_type="H100",
    timeout_seconds=3600
)

# Check status later
await execution.refresh()
if execution.is_complete:
    print(execution.output)
```

### Notebook Versioning

Git-like versioning for notebooks:

```python
# Save a version
version = await notebook.save(message="Added training loop")

# List versions
versions = await notebook.list_versions()

# Restore a version
await notebook.restore_version(version.id)

# Create a branch
await notebook.create_branch("experiment-v2", from_version_id=version.id)
```

### Projects

Organize notebooks into projects:

```python
# Create project
project = await client.create_project(
    name="ML Research",
    description="Transformer experiments"
)

# Create notebook in project
notebook = await client.notebooks.create(
    name="attention-study",
    gpu_type="A100",
    project_id=project.id
)

# List project notebooks
notebooks = await client.notebooks.list(project_id=project.id)
```

### Billing & Usage

```python
# Check balance
balance = await client.get_wallet_balance()
print(f"Balance: ₹{balance.balance:.2f}")

# Get usage
usage = await client.get_usage(
    start_date="2024-01-01",
    end_date="2024-01-31",
    group_by="day"
)
print(f"Total cost: ₹{usage.total_cost:.2f}")
```

### GPU Types

```python
# List available GPUs
gpus = await client.list_gpus()
for gpu in gpus:
    print(f"{gpu.type}: {gpu.memory_gb}GB, ₹{gpu.price_per_hour_paise/100:.2f}/hr")
```

Available GPU types:
- `T4` - 16GB, budget-friendly
- `L4` - 24GB, inference optimized
- `A10` - 24GB, balanced
- `A100_40GB` - 40GB, training
- `A100_80GB` - 80GB, large models
- `H100` - 80GB, fastest

### Webhooks

```python
# Create webhook
webhook = await client.create_webhook(
    url="https://your-server.com/webhook",
    events=["notebook.started", "execution.completed"]
)

# List webhooks
webhooks = await client.list_webhooks()
```

## Error Handling

```python
from podstack import (
    Client,
    PodstackError,
    AuthenticationError,
    GPUNotAvailableError,
    RateLimitError,
    ExecutionTimeoutError
)

try:
    async with Client(api_key="invalid") as client:
        await client.notebooks.create(name="test", gpu_type="A100")
except AuthenticationError:
    print("Invalid API key")
except GPUNotAvailableError as e:
    print(f"GPU {e.gpu_type} not available, try: {e.available_types}")
except RateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after}s")
except ExecutionTimeoutError as e:
    print(f"Execution {e.execution_id} timed out")
except PodstackError as e:
    print(f"Error [{e.code}]: {e.message}")
```

## Configuration

```python
# Environment variables
# PODSTACK_API_KEY=psk_live_xxxxx
# PODSTACK_BASE_URL=https://api.podstack.io/v1

# Or pass directly
client = Client(
    api_key="psk_live_xxxxx",
    base_url="https://api.podstack.io/v1",
    timeout=60.0,
    max_retries=5
)
```

## License

MIT License - see LICENSE for details.
