Metadata-Version: 2.4
Name: sed-sh
Version: 0.1.0
Summary: Official Python SDK for sed.sh API - URL shortening, malware scanning, disposable email, mock APIs, and PDF reports
Author-email: "sed.sh" <support@sed.sh>
License: MIT
Project-URL: Homepage, https://www.sed.sh
Project-URL: Documentation, https://www.sed.sh/docs
Project-URL: Repository, https://github.com/triellocom/sed-sh-sdk/tree/master/python
Project-URL: Issues, https://github.com/triellocom/sed-sh-sdk/issues
Keywords: sed.sh,url-shortener,malware-scanner,disposable-email,mock-api,pdf-generator,api-client
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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 :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Requires-Dist: aiohttp>=3.8.0
Requires-Dist: aiofiles>=23.0.0
Requires-Dist: click>=8.0.0
Requires-Dist: typing-extensions>=4.0.0; python_version < "3.10"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: pytest-mock>=3.10.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: types-requests>=2.25.0; extra == "dev"
Dynamic: license-file

# sed.sh Python SDK

Official Python client library for [sed.sh](https://www.sed.sh) API - providing URL shortening, malware scanning, disposable email, mock APIs, and PDF report generation.

[![PyPI version](https://badge.fury.io/py/sed-sh.svg)](https://badge.fury.io/py/sed-sh)
[![Python Versions](https://img.shields.io/pypi/pyversions/sed-sh.svg)](https://pypi.org/project/sed-sh/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- **Links**: Create, manage, and track shortened URLs with optional password protection
- **Malware Scanner**: Scan files for malware using AWS GuardDuty
- **Disposable Inbox**: Create temporary email addresses for testing
- **Mock APIs**: Create mock HTTP endpoints for testing and development
- **PDF Reports**: Generate PDF documents from HTML templates with JSON data
- **Both Sync and Async**: Full support for synchronous and asynchronous operations
- **CLI Tool**: Command-line interface for all services
- **Type Hints**: Full typing support for better IDE autocomplete

## Installation

```bash
pip install sed-sh
```

## Quick Start

### Synchronous Usage

```python
from sed_sh import SedSH

# Initialize client with API key
client = SedSH(api_key="your_api_key_here")

# Create a short link
link = client.links.create("https://example.com/very/long/url")
print(f"Short URL: {link['shortUrl']}")

# Scan a file for malware
scan = client.malware.scan_file("/path/to/file.pdf")
print(f"Scan status: {scan['status']}")

# Create a disposable inbox
inbox = client.inbox.create()
print(f"Email address: {inbox['email']}")

# Create a mock API endpoint
endpoint = client.routes.create_endpoint(
    name="Test API",
    method="POST",
    path="/api/test",
    response_status=200,
    response_body='{"success": true}'
)
print(f"Mock URL: {endpoint['url']}")

# Generate a PDF from template
template = client.reports.create_template(
    name="Invoice",
    html="<h1>Invoice for {{customer}}</h1>"
)
pdf = client.reports.generate_pdf(
    template['templateId'],
    {"customer": "John Doe"}
)
print(f"PDF URL: {pdf['downloadUrl']}")
```

### Asynchronous Usage

```python
import asyncio
from sed_sh import AsyncSedSH

async def main():
    # Initialize async client
    client = AsyncSedSH(api_key="your_api_key_here")

    # Create a short link
    link = await client.links.create("https://example.com")
    print(f"Short URL: {link['shortUrl']}")

    # Scan a file
    scan = await client.malware.scan_file("/path/to/file.pdf")
    print(f"Scan status: {scan['status']}")

    # Close the session when done
    await client.close()

asyncio.run(main())
```

### Using Context Managers

```python
# Sync context manager
with SedSH(api_key="your_api_key") as client:
    link = client.links.create("https://example.com")
    print(link['shortUrl'])

# Async context manager
async with AsyncSedSH(api_key="your_api_key") as client:
    link = await client.links.create("https://example.com")
    print(link['shortUrl'])
```

## Authentication

The SDK supports multiple authentication methods:

### 1. Constructor Parameter
```python
client = SedSH(api_key="your_api_key")
```

### 2. Environment Variable
```bash
export SEDSH_API_KEY="your_api_key"
```
```python
client = SedSH()  # Automatically uses SEDSH_API_KEY
```

### 3. Config File
Create `~/.sedsh/config.json`:
```json
{
  "api_key": "your_api_key",
  "base_url": "https://api.sed.sh"
}
```
```python
client = SedSH()  # Automatically loads from config file
```

## CLI Usage

The SDK includes a command-line interface:

```bash
# Set API key
export SEDSH_API_KEY="your_api_key"

# Links
sedsh links create https://example.com
sedsh links create https://example.com --password secret123
sedsh links list
sedsh links delete abc12

# Malware
sedsh malware scan /path/to/file.pdf

# Inbox
sedsh inbox create
sedsh inbox list
sedsh inbox messages <inbox-code>
sedsh inbox delete <inbox-code>

# Routes
sedsh routes create "Test API" POST /api/test --status 200 --body '{"ok": true}'
sedsh routes list
sedsh routes delete <endpoint-id>

# Reports
sedsh reports create-template "Invoice" /path/to/template.html
sedsh reports generate <template-id> '{"customer": "John"}'
sedsh reports list-templates
```

## API Reference

### Links Service

```python
# Create a link
link = client.links.create(
    target_url="https://example.com",
    password="optional_password"  # Optional
)

# List all links
links = client.links.list()

# Delete a link
client.links.delete(code="abc12")
```

### Malware Service

```python
# Scan a file
scan = client.malware.scan_file(
    file_path="/path/to/file.pdf"
)
# Returns: {'scanId': '...', 'status': 'pending', 'fileName': '...'}

# Note: Scan results are sent via email notification
```

### Inbox Service

```python
# Create an inbox
inbox = client.inbox.create()

# List all inboxes
inboxes = client.inbox.list()

# Get messages for an inbox
messages = client.inbox.get_messages(inbox_code="inbox_123")

# Get a specific message
message = client.inbox.get_message(
    inbox_code="inbox_123",
    message_id="msg_456"
)

# Delete a message
client.inbox.delete_message(
    inbox_code="inbox_123",
    message_id="msg_456"
)

# Delete an inbox
client.inbox.delete(inbox_code="inbox_123")
```

### Routes Service

```python
# Create a mock endpoint
endpoint = client.routes.create_endpoint(
    name="User API",
    method="POST",
    path="/api/users",
    response_status=200,
    response_body='{"success": true}',
    response_headers={"Content-Type": "application/json"},  # Optional
    response_delay=0,  # Optional, milliseconds
    enabled=True  # Optional
)

# Create a forward endpoint (proxy mode)
endpoint = client.routes.create_endpoint(
    name="Proxy API",
    method="GET",
    path="/api/proxy",
    forward_mode=True,
    forward_url="https://api.example.com/endpoint"
)

# List endpoints
endpoints = client.routes.list_endpoints()

# Update an endpoint
updated = client.routes.update_endpoint(
    endpoint_id="endpoint_123",
    name="Updated API",
    response_status=201
)

# Toggle endpoint enabled/disabled
client.routes.toggle_endpoint(
    endpoint_id="endpoint_123",
    enabled=False
)

# Get requests received by endpoints
requests = client.routes.get_requests()

# Get details of a specific request
request_details = client.routes.get_request(request_id="req_123")

# Delete an endpoint
client.routes.delete_endpoint(endpoint_id="endpoint_123")
```

### Reports Service

```python
# Create a template
template = client.reports.create_template(
    name="Invoice Template",
    html="<h1>Invoice #{{invoice_number}}</h1>",
    expiry_hours=24  # Optional, max 24
)

# List templates
templates = client.reports.list_templates()

# Get template HTML
html = client.reports.get_template(template_id="tpl_123")

# Generate PDF from template
pdf = client.reports.generate_pdf(
    template_id="tpl_123",
    data={
        "invoice_number": "INV-001",
        "customer": "John Doe",
        "amount": "$100.00"
    }
)
# Returns: {'downloadUrl': '...', 'generationId': '...', 'expiresAt': ...}

# List recent PDF generations
generations = client.reports.list_generations()

# Delete a template
client.reports.delete_template(template_id="tpl_123")
```

## Error Handling

```python
from sed_sh import SedSH
from sed_sh.exceptions import (
    SedSHError,
    AuthenticationError,
    RateLimitError,
    ResourceNotFoundError,
    InvalidRequestError,
)

client = SedSH(api_key="your_api_key")

try:
    link = client.links.create("https://example.com")
except AuthenticationError as e:
    print(f"Invalid API key: {e}")
except RateLimitError as e:
    print(f"Rate limit exceeded: {e}")
except ResourceNotFoundError as e:
    print(f"Resource not found: {e}")
except InvalidRequestError as e:
    print(f"Invalid request: {e}")
except SedSHError as e:
    print(f"API error: {e}")
```

## Important Notes

⚠️ **This SDK does NOT include automatic retries or request timeouts**. You should implement these in your application if needed:

```python
# Example: Manual retry logic
from time import sleep

def create_link_with_retry(client, url, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.links.create(url)
        except SedSHError as e:
            if attempt == max_retries - 1:
                raise
            sleep(2 ** attempt)  # Exponential backoff
```

⚠️ **This SDK does NOT perform client-side input validation**. Invalid inputs will be caught by the API and return appropriate errors.

## Configuration Options

```python
client = SedSH(
    api_key="your_api_key",          # API key (required if not in env/config)
    base_url="https://api.sed.sh",   # API base URL (optional)
    timeout=30,                       # Request timeout in seconds (optional)
)
```

## Development

```bash
# Clone the repository
git clone https://github.com/triellocom/sed-sh-sdk.git
cd sed-sh-sdk/python

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest

# Format code
black sed_sh/

# Type checking
mypy sed_sh/
```

## Examples

See the [`examples/`](./examples) directory for complete examples:

- `links_sync.py` - Synchronous link management
- `links_async.py` - Asynchronous link management
- `malware_sync.py` - File scanning
- `inbox_sync.py` - Disposable email management
- `routes_sync.py` - Mock API endpoint creation
- `reports_sync.py` - PDF generation

## Requirements

- Python 3.8 or higher
- `requests` >= 2.25.0
- `aiohttp` >= 3.8.0
- `click` >= 8.0.0

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Support

- Documentation: https://www.sed.sh/docs
- Issues: https://github.com/triellocom/sed-sh-sdk/issues
- Email: support@sed.sh

## Links

- Website: https://www.sed.sh
- API Documentation: https://www.sed.sh/docs
- PyPI: https://pypi.org/project/sed-sh/

## Testing

The SDK includes a comprehensive test suite using pytest.

### Running Tests

```bash
# Install development dependencies
pip install -e .[dev]

# Run all tests
make test

# Run with coverage
make test-cov

# Run integration tests (requires API key)
export SEDSH_API_KEY="your-api-key"
make test-integration
```

### Test Structure

- `tests/test_exceptions.py` - Exception handling tests
- `tests/test_client.py` - Client initialization tests
- `tests/test_services_integration.py` - API integration tests

See [README_TESTING.md](README_TESTING.md) for detailed testing documentation.
