synthefy


Namesynthefy JSON
Version 2.0.4 PyPI version JSON
download
home_pageNone
SummaryPython client for the Synthefy API forecasting service
upload_time2025-10-07 01:39:09
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT
keywords api forecasting machine-learning time-series
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Synthefy Python Client

A Python client for the Synthefy API forecasting service. This package provides an easy-to-use interface for making time series forecasting requests with both synchronous and asynchronous support.

## Features

- **Sync & Async Support**: Separate clients for synchronous and asynchronous operations
- **Professional Error Handling**: Comprehensive exception hierarchy with detailed error messages
- **Retry Logic**: Built-in exponential backoff for transient errors (rate limits, server errors)
- **Context Managers**: Automatic resource cleanup with `with` and `async with` statements
- **Pandas Integration**: Built-in support for pandas DataFrames
- **Type Safety**: Full type hints and Pydantic validation

## Installation

```bash
pip install synthefy
```

## Quick Start

### Basic Usage

```python
from synthefy import SynthefyAPIClient, SynthefyAsyncAPIClient
import pandas as pd

# Synchronous client
with SynthefyAPIClient(api_key="your_api_key_here") as client:
    # Make requests...
    pass

# Asynchronous client
async with SynthefyAsyncAPIClient() as client:  # Uses SYNTHEFY_API_KEY env var
    # Make async requests...
    pass
```

### Making a Forecast Request

```python
from synthefy import SynthefyAPIClient
import pandas as pd
import numpy as np

# Create sample data with numeric metadata
history_data = {
    'date': pd.date_range('2024-01-01', periods=100, freq='D'),
    'sales': np.random.normal(100, 10, 100),
    'store_id': 1,
    'category_id': 101,
    'promotion_active': 0
}

target_data = {
    'date': pd.date_range('2024-04-11', periods=30, freq='D'),
    'sales': np.nan,  # Values to forecast
    'store_id': 1,
    'category_id': 101,
    'promotion_active': 1  # Promotion active in forecast period
}

history_df = pd.DataFrame(history_data)
target_df = pd.DataFrame(target_data)

# Synchronous forecast
with SynthefyAPIClient() as client:
    forecast_dfs = client.forecast_dfs(
        history_dfs=[history_df],
        target_dfs=[target_df],
        target_col='sales',
        timestamp_col='date',
        metadata_cols=['store_id', 'category_id', 'promotion_active'],
        leak_cols=[],
        model='sfm-moe-v1'
    )

# Result is a list of DataFrames with forecasts
forecast_df = forecast_dfs[0]
print(forecast_df[['timestamps', 'sales']].head())
```

### Asynchronous Usage

```python
import asyncio
from synthefy.api_client import SynthefyAsyncAPIClient

async def main():
    async with SynthefyAsyncAPIClient() as client:
        # Single async forecast
        forecast_dfs = await client.forecast_dfs(
            history_dfs=[history_df],
            target_dfs=[target_df],
            target_col='sales',
            timestamp_col='date',
            metadata_cols=['store_id', 'category_id', 'promotion_active'],
            leak_cols=[],
            model='sfm-moe-v1'
        )

        # Concurrent forecasts for multiple datasets
        tasks = []
        for i in range(3):
            # Create variations of your data
            modified_history = history_df.copy()
            modified_target = target_df.copy()
            modified_history['store_id'] = i + 1
            modified_target['store_id'] = i + 1

            task = client.forecast_dfs(
                history_dfs=[modified_history],
                target_dfs=[modified_target],
                target_col='sales',
                timestamp_col='date',
                metadata_cols=['store_id', 'category_id', 'promotion_active'],
                leak_cols=[],
                model='sfm-moe-v1'
            )
            tasks.append(task)

        # Execute all forecasts concurrently
        results = await asyncio.gather(*tasks)

        for i, forecast_dfs in enumerate(results):
            print(f"Forecast for store {i+1}: {len(forecast_dfs[0])} predictions")

# Run the async function
asyncio.run(main())
```

### Backtesting

```python
import asyncio
import pandas as pd
import numpy as np
from synthefy.data_models import ForecastV2Request
from synthefy.api_client import SynthefyAsyncAPIClient

async def main():

    # Create sample time series data
    dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')
    data = {
        'date': dates,
        'sales': np.random.normal(100, 10, len(dates)),
        'store_id': 1,
        'category_id': 101,
        'promotion_active': np.random.choice([0, 1], len(dates), p=[0.7, 0.3])
    }
    df = pd.DataFrame(data)

    print(f"Created dataset with {len(df)} rows from {df['date'].min()} to {df['date'].max()}")

    # Use from_dfs_pre_split for backtesting with date-based windows
    request = ForecastV2Request.from_dfs_pre_split(
        dfs=[df],
        timestamp_col='date',
        target_cols=['sales'],
        model='sfm-moe-v1',
        cutoff_date='2023-06-01',  # Start backtesting from June 1st
        forecast_window='7D',      # 7-day forecast windows
        stride='14D',              # Move forward 14 days between windows
        metadata_cols=['store_id', 'category_id', 'promotion_active'],
        leak_cols=['promotion_active']  # Promotion data may leak into target
    )

    print(f"Created {len(request.samples)} forecast windows for backtesting")
    print("Window details:")
    for i, sample in enumerate(request.samples):
        history_start = sample[0].history_timestamps[0]
        history_end = sample[0].history_timestamps[-1]
        target_start = sample[0].target_timestamps[0]
        target_end = sample[0].target_timestamps[-1]
        print(f"  Window {i+1}: History {history_start} to {history_end}, Target {target_start} to {target_end}")

    # Make async forecast request
    async with SynthefyAsyncAPIClient() as client:
        response = await client.forecast(request)

        print(f"\nBacktesting completed with {len(response.samples)} forecast windows")

        # Process results for each window
        for i, sample in enumerate(response.samples):
            print(f"Window {i+1}: {len(sample.history_timestamps)} history points, "
                f"{len(sample.target_timestamps)} target points")

            # Access forecast values
            if hasattr(sample, 'forecast_values') and sample.forecast_values:
                print(f"  Forecast values: {sample.forecast_values[:3]}...")  # First 3 values
asyncio.run(main())
```

### Advanced Configuration

```python
from synthefy import SynthefyAPIClient
from synthefy.api_client import BadRequestError, RateLimitError

# Client with custom configuration
with SynthefyAPIClient(
    api_key="your_key",
    timeout=600.0,  # 10 minutes
    max_retries=3,
    organization="your_org_id",
    base_url="https://custom.synthefy.com"  # For enterprise customers
) as client:
    try:
        # Per-request configuration
        forecast_dfs = client.forecast_dfs(
            history_dfs=[history_df],
            target_dfs=[target_df],
            target_col='sales',
            timestamp_col='date',
            metadata_cols=['store_id'],
            leak_cols=[],
            model='sfm-moe-v1',
            timeout=120.0,  # Override client timeout for this request
            idempotency_key="unique-request-id",  # Prevent duplicate processing
            extra_headers={"X-Custom-Header": "value"}
        )
    except BadRequestError as e:
        print(f"Invalid request: {e}")
        print(f"Status code: {e.status_code}")
        print(f"Request ID: {e.request_id}")
    except RateLimitError as e:
        print(f"Rate limited: {e}")
        # Client automatically retries with exponential backoff
    except Exception as e:
        print(f"Unexpected error: {e}")
```

## API Reference

### SynthefyAPIClient (Synchronous)

The synchronous client class for interacting with the Synthefy API.

#### Constructor Parameters

- `api_key`: Your Synthefy API key (can also be set via `SYNTHEFY_API_KEY` environment variable)
- `timeout`: Request timeout in seconds (default: 300.0 / 5 minutes)
- `max_retries`: Number of retries for transient errors (default: 2)
- `base_url`: API base URL (default: "https://prod.synthefy.com")
- `organization`: Optional organization ID for multi-tenant setups
- `user_agent`: Custom user agent string

#### Methods

- `forecast(request, *, timeout=None, idempotency_key=None, extra_headers=None) -> ForecastV2Response`
  - Make a direct forecast request with a `ForecastV2Request` object
- `forecast_dfs(history_dfs, target_dfs, target_col, timestamp_col, metadata_cols, leak_cols, model) -> List[pd.DataFrame]`
  - Convenience method for working directly with pandas DataFrames
- `close()`: Manually close the HTTP client
- Context manager support: Use with `with SynthefyAPIClient() as client:`

### SynthefyAsyncAPIClient (Asynchronous)

The asynchronous client class for non-blocking operations and concurrent requests.

#### Constructor Parameters

Same as `SynthefyAPIClient`.

#### Methods

- `async forecast(request, *, timeout=None, idempotency_key=None, extra_headers=None) -> ForecastV2Response`
  - Async version of forecast method
- `async forecast_dfs(history_dfs, target_dfs, target_col, timestamp_col, metadata_cols, leak_cols, model) -> List[pd.DataFrame]`
  - Async version of forecast_dfs method
- `async aclose()`: Manually close the async HTTP client
- Async context manager support: Use with `async with SynthefyAsyncAPIClient() as client:`

### Exception Hierarchy

All exceptions inherit from `SynthefyError`:

- `APITimeoutError`: Request timed out
- `APIConnectionError`: Network/connection issues
- `APIStatusError`: Base class for HTTP status errors
  - `BadRequestError` (400, 422): Invalid request data
  - `AuthenticationError` (401): Invalid API key
  - `PermissionDeniedError` (403): Access denied
  - `NotFoundError` (404): Resource not found
  - `RateLimitError` (429): Rate limit exceeded
  - `InternalServerError` (5xx): Server errors

Each status error includes:
- `status_code`: HTTP status code
- `request_id`: Request ID for debugging (if available)
- `error_code`: API-specific error code (if available)
- `response_body`: Raw response body

## Configuration

### Environment Variables

- `SYNTHEFY_API_KEY`: Your Synthefy API key

## Support

For support and questions:
- Email: contact@synthefy.com

## License

MIT License - see LICENSE file for details.
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "synthefy",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": "Synthefy <contact@synthefy.com>",
    "keywords": "api, forecasting, machine-learning, time-series",
    "author": null,
    "author_email": "Synthefy <contact@synthefy.com>",
    "download_url": "https://files.pythonhosted.org/packages/c3/07/a54985f20b84dcabd786b8961afd1c4552837ab7bdafda6662355e606440/synthefy-2.0.4.tar.gz",
    "platform": null,
    "description": "# Synthefy Python Client\n\nA Python client for the Synthefy API forecasting service. This package provides an easy-to-use interface for making time series forecasting requests with both synchronous and asynchronous support.\n\n## Features\n\n- **Sync & Async Support**: Separate clients for synchronous and asynchronous operations\n- **Professional Error Handling**: Comprehensive exception hierarchy with detailed error messages\n- **Retry Logic**: Built-in exponential backoff for transient errors (rate limits, server errors)\n- **Context Managers**: Automatic resource cleanup with `with` and `async with` statements\n- **Pandas Integration**: Built-in support for pandas DataFrames\n- **Type Safety**: Full type hints and Pydantic validation\n\n## Installation\n\n```bash\npip install synthefy\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nfrom synthefy import SynthefyAPIClient, SynthefyAsyncAPIClient\nimport pandas as pd\n\n# Synchronous client\nwith SynthefyAPIClient(api_key=\"your_api_key_here\") as client:\n    # Make requests...\n    pass\n\n# Asynchronous client\nasync with SynthefyAsyncAPIClient() as client:  # Uses SYNTHEFY_API_KEY env var\n    # Make async requests...\n    pass\n```\n\n### Making a Forecast Request\n\n```python\nfrom synthefy import SynthefyAPIClient\nimport pandas as pd\nimport numpy as np\n\n# Create sample data with numeric metadata\nhistory_data = {\n    'date': pd.date_range('2024-01-01', periods=100, freq='D'),\n    'sales': np.random.normal(100, 10, 100),\n    'store_id': 1,\n    'category_id': 101,\n    'promotion_active': 0\n}\n\ntarget_data = {\n    'date': pd.date_range('2024-04-11', periods=30, freq='D'),\n    'sales': np.nan,  # Values to forecast\n    'store_id': 1,\n    'category_id': 101,\n    'promotion_active': 1  # Promotion active in forecast period\n}\n\nhistory_df = pd.DataFrame(history_data)\ntarget_df = pd.DataFrame(target_data)\n\n# Synchronous forecast\nwith SynthefyAPIClient() as client:\n    forecast_dfs = client.forecast_dfs(\n        history_dfs=[history_df],\n        target_dfs=[target_df],\n        target_col='sales',\n        timestamp_col='date',\n        metadata_cols=['store_id', 'category_id', 'promotion_active'],\n        leak_cols=[],\n        model='sfm-moe-v1'\n    )\n\n# Result is a list of DataFrames with forecasts\nforecast_df = forecast_dfs[0]\nprint(forecast_df[['timestamps', 'sales']].head())\n```\n\n### Asynchronous Usage\n\n```python\nimport asyncio\nfrom synthefy.api_client import SynthefyAsyncAPIClient\n\nasync def main():\n    async with SynthefyAsyncAPIClient() as client:\n        # Single async forecast\n        forecast_dfs = await client.forecast_dfs(\n            history_dfs=[history_df],\n            target_dfs=[target_df],\n            target_col='sales',\n            timestamp_col='date',\n            metadata_cols=['store_id', 'category_id', 'promotion_active'],\n            leak_cols=[],\n            model='sfm-moe-v1'\n        )\n\n        # Concurrent forecasts for multiple datasets\n        tasks = []\n        for i in range(3):\n            # Create variations of your data\n            modified_history = history_df.copy()\n            modified_target = target_df.copy()\n            modified_history['store_id'] = i + 1\n            modified_target['store_id'] = i + 1\n\n            task = client.forecast_dfs(\n                history_dfs=[modified_history],\n                target_dfs=[modified_target],\n                target_col='sales',\n                timestamp_col='date',\n                metadata_cols=['store_id', 'category_id', 'promotion_active'],\n                leak_cols=[],\n                model='sfm-moe-v1'\n            )\n            tasks.append(task)\n\n        # Execute all forecasts concurrently\n        results = await asyncio.gather(*tasks)\n\n        for i, forecast_dfs in enumerate(results):\n            print(f\"Forecast for store {i+1}: {len(forecast_dfs[0])} predictions\")\n\n# Run the async function\nasyncio.run(main())\n```\n\n### Backtesting\n\n```python\nimport asyncio\nimport pandas as pd\nimport numpy as np\nfrom synthefy.data_models import ForecastV2Request\nfrom synthefy.api_client import SynthefyAsyncAPIClient\n\nasync def main():\n\n    # Create sample time series data\n    dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')\n    data = {\n        'date': dates,\n        'sales': np.random.normal(100, 10, len(dates)),\n        'store_id': 1,\n        'category_id': 101,\n        'promotion_active': np.random.choice([0, 1], len(dates), p=[0.7, 0.3])\n    }\n    df = pd.DataFrame(data)\n\n    print(f\"Created dataset with {len(df)} rows from {df['date'].min()} to {df['date'].max()}\")\n\n    # Use from_dfs_pre_split for backtesting with date-based windows\n    request = ForecastV2Request.from_dfs_pre_split(\n        dfs=[df],\n        timestamp_col='date',\n        target_cols=['sales'],\n        model='sfm-moe-v1',\n        cutoff_date='2023-06-01',  # Start backtesting from June 1st\n        forecast_window='7D',      # 7-day forecast windows\n        stride='14D',              # Move forward 14 days between windows\n        metadata_cols=['store_id', 'category_id', 'promotion_active'],\n        leak_cols=['promotion_active']  # Promotion data may leak into target\n    )\n\n    print(f\"Created {len(request.samples)} forecast windows for backtesting\")\n    print(\"Window details:\")\n    for i, sample in enumerate(request.samples):\n        history_start = sample[0].history_timestamps[0]\n        history_end = sample[0].history_timestamps[-1]\n        target_start = sample[0].target_timestamps[0]\n        target_end = sample[0].target_timestamps[-1]\n        print(f\"  Window {i+1}: History {history_start} to {history_end}, Target {target_start} to {target_end}\")\n\n    # Make async forecast request\n    async with SynthefyAsyncAPIClient() as client:\n        response = await client.forecast(request)\n\n        print(f\"\\nBacktesting completed with {len(response.samples)} forecast windows\")\n\n        # Process results for each window\n        for i, sample in enumerate(response.samples):\n            print(f\"Window {i+1}: {len(sample.history_timestamps)} history points, \"\n                f\"{len(sample.target_timestamps)} target points\")\n\n            # Access forecast values\n            if hasattr(sample, 'forecast_values') and sample.forecast_values:\n                print(f\"  Forecast values: {sample.forecast_values[:3]}...\")  # First 3 values\nasyncio.run(main())\n```\n\n### Advanced Configuration\n\n```python\nfrom synthefy import SynthefyAPIClient\nfrom synthefy.api_client import BadRequestError, RateLimitError\n\n# Client with custom configuration\nwith SynthefyAPIClient(\n    api_key=\"your_key\",\n    timeout=600.0,  # 10 minutes\n    max_retries=3,\n    organization=\"your_org_id\",\n    base_url=\"https://custom.synthefy.com\"  # For enterprise customers\n) as client:\n    try:\n        # Per-request configuration\n        forecast_dfs = client.forecast_dfs(\n            history_dfs=[history_df],\n            target_dfs=[target_df],\n            target_col='sales',\n            timestamp_col='date',\n            metadata_cols=['store_id'],\n            leak_cols=[],\n            model='sfm-moe-v1',\n            timeout=120.0,  # Override client timeout for this request\n            idempotency_key=\"unique-request-id\",  # Prevent duplicate processing\n            extra_headers={\"X-Custom-Header\": \"value\"}\n        )\n    except BadRequestError as e:\n        print(f\"Invalid request: {e}\")\n        print(f\"Status code: {e.status_code}\")\n        print(f\"Request ID: {e.request_id}\")\n    except RateLimitError as e:\n        print(f\"Rate limited: {e}\")\n        # Client automatically retries with exponential backoff\n    except Exception as e:\n        print(f\"Unexpected error: {e}\")\n```\n\n## API Reference\n\n### SynthefyAPIClient (Synchronous)\n\nThe synchronous client class for interacting with the Synthefy API.\n\n#### Constructor Parameters\n\n- `api_key`: Your Synthefy API key (can also be set via `SYNTHEFY_API_KEY` environment variable)\n- `timeout`: Request timeout in seconds (default: 300.0 / 5 minutes)\n- `max_retries`: Number of retries for transient errors (default: 2)\n- `base_url`: API base URL (default: \"https://prod.synthefy.com\")\n- `organization`: Optional organization ID for multi-tenant setups\n- `user_agent`: Custom user agent string\n\n#### Methods\n\n- `forecast(request, *, timeout=None, idempotency_key=None, extra_headers=None) -> ForecastV2Response`\n  - Make a direct forecast request with a `ForecastV2Request` object\n- `forecast_dfs(history_dfs, target_dfs, target_col, timestamp_col, metadata_cols, leak_cols, model) -> List[pd.DataFrame]`\n  - Convenience method for working directly with pandas DataFrames\n- `close()`: Manually close the HTTP client\n- Context manager support: Use with `with SynthefyAPIClient() as client:`\n\n### SynthefyAsyncAPIClient (Asynchronous)\n\nThe asynchronous client class for non-blocking operations and concurrent requests.\n\n#### Constructor Parameters\n\nSame as `SynthefyAPIClient`.\n\n#### Methods\n\n- `async forecast(request, *, timeout=None, idempotency_key=None, extra_headers=None) -> ForecastV2Response`\n  - Async version of forecast method\n- `async forecast_dfs(history_dfs, target_dfs, target_col, timestamp_col, metadata_cols, leak_cols, model) -> List[pd.DataFrame]`\n  - Async version of forecast_dfs method\n- `async aclose()`: Manually close the async HTTP client\n- Async context manager support: Use with `async with SynthefyAsyncAPIClient() as client:`\n\n### Exception Hierarchy\n\nAll exceptions inherit from `SynthefyError`:\n\n- `APITimeoutError`: Request timed out\n- `APIConnectionError`: Network/connection issues\n- `APIStatusError`: Base class for HTTP status errors\n  - `BadRequestError` (400, 422): Invalid request data\n  - `AuthenticationError` (401): Invalid API key\n  - `PermissionDeniedError` (403): Access denied\n  - `NotFoundError` (404): Resource not found\n  - `RateLimitError` (429): Rate limit exceeded\n  - `InternalServerError` (5xx): Server errors\n\nEach status error includes:\n- `status_code`: HTTP status code\n- `request_id`: Request ID for debugging (if available)\n- `error_code`: API-specific error code (if available)\n- `response_body`: Raw response body\n\n## Configuration\n\n### Environment Variables\n\n- `SYNTHEFY_API_KEY`: Your Synthefy API key\n\n## Support\n\nFor support and questions:\n- Email: contact@synthefy.com\n\n## License\n\nMIT License - see LICENSE file for details.",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python client for the Synthefy API forecasting service",
    "version": "2.0.4",
    "project_urls": {
        "Homepage": "https://synthefy.com"
    },
    "split_keywords": [
        "api",
        " forecasting",
        " machine-learning",
        " time-series"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e014ae572577dae1f1e00fb498ea39822dafab8a0d150ba587dbb395c9f1e4e1",
                "md5": "1098b83fca5e3f794fd26d6e2c9cfbc7",
                "sha256": "9b745e9d47f2a9cfc2d30e5391834cf40f3b154e341a4eadcff897dcfa12b692"
            },
            "downloads": -1,
            "filename": "synthefy-2.0.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1098b83fca5e3f794fd26d6e2c9cfbc7",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 19350,
            "upload_time": "2025-10-07T01:39:08",
            "upload_time_iso_8601": "2025-10-07T01:39:08.170913Z",
            "url": "https://files.pythonhosted.org/packages/e0/14/ae572577dae1f1e00fb498ea39822dafab8a0d150ba587dbb395c9f1e4e1/synthefy-2.0.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c307a54985f20b84dcabd786b8961afd1c4552837ab7bdafda6662355e606440",
                "md5": "19c235b4a6eb4257d8f65d0845c61405",
                "sha256": "66ebc22ea9e8fbd7472ed0556355c9a9e0d0c6d7e21aac406d069d921c647f74"
            },
            "downloads": -1,
            "filename": "synthefy-2.0.4.tar.gz",
            "has_sig": false,
            "md5_digest": "19c235b4a6eb4257d8f65d0845c61405",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 18166,
            "upload_time": "2025-10-07T01:39:09",
            "upload_time_iso_8601": "2025-10-07T01:39:09.341901Z",
            "url": "https://files.pythonhosted.org/packages/c3/07/a54985f20b84dcabd786b8961afd1c4552837ab7bdafda6662355e606440/synthefy-2.0.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-07 01:39:09",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "synthefy"
}
        
Elapsed time: 1.08058s