aiopythonik


Nameaiopythonik JSON
Version 2025.7b1 PyPI version JSON
download
home_pageNone
SummaryAsynchronous wrapper for NSA's pythonik client library
upload_time2025-07-30 00:49:07
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseMIT
keywords iconik api pythonik nsa-pythonik asynchronous
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # aiopythonik

Asynchronous wrapper for the
[pythonik](https://pypi.org/project/nsa-pythonik/) library, enabling its
use in async Python applications without blocking the event loop.

[![PyPI Version](https://img.shields.io/pypi/v/aiopythonik.svg)](https://pypi.org/project/aiopythonik/)
[![Python Versions](https://img.shields.io/pypi/pyversions/aiopythonik.svg)](https://pypi.org/project/aiopythonik/)
[![License](https://img.shields.io/pypi/l/aiopythonik.svg)](https://pypi.org/project/aiopythonik/)

## Overview

`aiopythonik` provides asynchronous versions of pythonik functionality
by wrapping the synchronous operations in a thread pool executor. This
approach is similar to how `aioboto3` wraps `boto3`, allowing you to use
asynchronous syntax while maintaining the original library's
capabilities.

### Features

- Complete async API for the pythonik library
- Automatic thread pool management for non-blocking operations
- Built-in rate limit handling with proactive throttling and
  configurable retry strategies
- Extended functionality through patched pythonik methods
- Support for Python 3.11+

## Installation

### Requirements

- Python 3.11 or higher

```bash
# Install from PyPI (recommended for most users)
pip install aiopythonik
```

The required dependency `nsa-pythonik` will be automatically installed.

### Installing from Source

For development or to get the latest unreleased changes:

```bash
# Clone the repository
git clone https://bitbucket.org/chesa/aiopythonik.git
cd aiopythonik

# Install in development mode
pip install -e .

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

## Quickstart

```python
import asyncio
from aiopythonik import AsyncPythonikClient

async def main():
    # Initialize the client
    client = AsyncPythonikClient(
        app_id="your_app_id",
        auth_token="your_auth_token",
        timeout=60,
        base_url="https://app.iconik.io",
    )

    try:
        # Use async methods
        asset = await client.assets().get("asset_id")
        print(f"Asset title: {asset.data.title}")

        # Get files for the asset
        files = await client.files().get_asset_files("asset_id")
        print(f"Number of files: {len(files.data.files)}")

        # Search for assets
        from pythonik.models.search.search_body import SearchBody
        search_results = await client.search().search(
            SearchBody(doc_types=["assets"], query="title:sample")
        )
        print(f"Found {len(search_results.data.objects)} assets")

    finally:
        # Always close the client when done
        await client.close()

if __name__ == "__main__":
    asyncio.run(main())
```

## Using the Context Manager

For convenience, you can use the async context manager to ensure proper
cleanup:

```python
import asyncio
from aiopythonik import AsyncPythonikClientContext

async def main():
    async with AsyncPythonikClientContext(
        app_id="your_app_id",
        auth_token="your_auth_token",
        timeout=60,
        base_url="https://app.iconik.io",
    ) as client:
        # Use async methods
        asset = await client.assets().get("asset_id")
        print(f"Asset title: {asset.data.title}")

if __name__ == "__main__":
    asyncio.run(main())
```

## API Coverage

`aiopythonik` provides async wrappers for all pythonik APIs and extends
functionality with some additional methods. Each API from the original
library is accessible through the corresponding async wrapper:

```python
# Assets
asset = await client.assets().get("asset_id")
assets = await client.assets().fetch(params={"per_page": 50})  # Enhanced method
await client.assets().delete("asset_id")

# Collections
collection = await client.collections().get("collection_id")
info = await client.collections().get_info("collection_id")
contents = await client.collections().get_contents("collection_id")

# Files
files = await client.files().get_asset_files("asset_id")
# Enhanced method with automatic checksum calculation
files_by_checksum = await client.files().get_files_by_checksum("d41d8cd98f00b204e9800998ecf8427e")
# Or calculate checksum automatically from a file
files_by_file = await client.files().get_files_by_checksum("path/to/file.mp4")

# Metadata
views = await client.metadata().get_views()
view = await client.metadata().get_view("view_id")
metadata = await client.metadata().get_asset_metadata("asset_id", "view_id")

# Jobs
job = await client.jobs().get("job_id")
await client.jobs().cancel("job_id")
```

### Automatic Rate Limit Handling

The library includes built-in handling for API rate limits with both
**proactive throttling** and **reactive retry logic**:

```python
from aiopythonik import AsyncPythonikClient, RateLimitConfig

# Configure custom rate limiting behavior
rate_limit_config = RateLimitConfig(
    max_retries=5,                      # Maximum number of retries for rate-limited requests
    initial_backoff=1.0,                # Initial backoff in seconds
    max_backoff=30.0,                   # Maximum backoff in seconds
    backoff_factor=2.0,                 # Exponential backoff factor
    jitter=True,                        # Add randomness to backoff times
    enable_proactive_throttling=True,   # Enable proactive throttling (default: True)
    proactive_throttling_threshold=0.8, # Start throttling at 80% quota usage
    max_proactive_delay=5.0             # Maximum proactive delay in seconds
)

client = AsyncPythonikClient(
    app_id="your_app_id",
    auth_token="your_auth_token",
    rate_limit_config=rate_limit_config
)

# Rate-limited requests will automatically be handled with:
# 1. Proactive throttling - slows down requests before hitting limits
# 2. Retry logic - handles 429 errors with exponential backoff
```

#### Proactive Throttling

The library automatically monitors your API quota usage through
`RateLimit-Remaining` headers and applies graduated delays **before**
hitting rate limits:

- **80%+ quota remaining**: No delay (full speed)
- **30-20% quota remaining**: Light throttling (0.1-0.5s delays)
- **20-10% quota remaining**: Moderate throttling (0.5-2.0s delays)
- **<10% quota remaining**: Aggressive throttling (2.0-5.0s delays)

This prevents 429 errors instead of just reacting to them, resulting in:

- Faster overall operations (no waiting for 5+ second retry delays)
- More predictable request timing
- Better resource efficiency
- Reduced server load

```python
# Proactive throttling can be disabled if needed
rate_limit_config = RateLimitConfig(
    enable_proactive_throttling=False  # Disable proactive throttling
)
```

## Advanced Usage

### Concurrent Operations

Running multiple operations concurrently:

```python
import asyncio
from aiopythonik import AsyncPythonikClientContext

async def main():
    async with AsyncPythonikClientContext(
        app_id="your_app_id",
        auth_token="your_auth_token",
    ) as client:
        # Run multiple operations concurrently
        asset_ids = ["id1", "id2", "id3", "id4", "id5"]

        tasks = [client.assets().get(asset_id) for asset_id in asset_ids]
        results = await asyncio.gather(*tasks)

        for i, result in enumerate(results):
            print(f"Asset {i+1}: {result.data.title}")

if __name__ == "__main__":
    asyncio.run(main())
```

### Custom Base URL

If you need to use a different API endpoint:

```python
client = AsyncPythonikClient(
    app_id="your_app_id",
    auth_token="your_auth_token",
    base_url="https://custom.iconik.io"
)
```

### Customizing Thread Pool Size

Control the maximum number of worker threads:

```python
client = AsyncPythonikClient(
    app_id="your_app_id",
    auth_token="your_auth_token",
    max_workers=10  # Set maximum number of worker threads
)
```

## Rate Limiting Details

The iconik APIs implement rate limiting to prevent individual users from
negatively impacting system performance. By default, the `aiopythonik`
library includes automatic handling of rate limits using a retry
strategy with exponential backoff.

Rate limits are enforced per authenticated user and application token:

- 50 requests per second sustained
- 1000 requests over any 20 second period

The library uses a **hybrid approach** to handle these limits:

1. **Proactive Throttling**: Monitors `RateLimit-Remaining` headers and
   gradually slows down requests as you approach the limit, preventing
   429 errors from occurring
2. **Reactive Retry Logic**: If 429 errors still occur, automatically
   retries with exponential backoff

This combination provides optimal performance - prevention when
possible, recovery when necessary.

You can disable automatic rate limit handling if you prefer to manage it
yourself:

```python
# Disable all rate limit handling
client = AsyncPythonikClient(
    app_id="your_app_id",
    auth_token="your_auth_token",
    disable_rate_limit_handling=True
)

# Or disable only proactive throttling while keeping retry logic
rate_limit_config = RateLimitConfig(
    enable_proactive_throttling=False,  # Disable proactive throttling
    max_retries=3                       # Keep retry logic
)
client = AsyncPythonikClient(
    app_id="your_app_id",
    auth_token="your_auth_token",
    rate_limit_config=rate_limit_config
)
```

## License

MIT

## Contributing

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

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "aiopythonik",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": "Product Team <product@chesa.com>, \"Chesapeake Systems, LLC\" <info@chesa.com>",
    "keywords": "iconik, api, pythonik, nsa-pythonik, asynchronous",
    "author": null,
    "author_email": "\"Brian F. Summa\" <brian.f.summa@chesa.com>",
    "download_url": "https://files.pythonhosted.org/packages/1d/2f/a898f8514b3d6910d3dabbfc6f78aec9f2ec0df2312c7a6a1fbe0e3103cd/aiopythonik-2025.7b1.tar.gz",
    "platform": null,
    "description": "# aiopythonik\n\nAsynchronous wrapper for the\n[pythonik](https://pypi.org/project/nsa-pythonik/) library, enabling its\nuse in async Python applications without blocking the event loop.\n\n[![PyPI Version](https://img.shields.io/pypi/v/aiopythonik.svg)](https://pypi.org/project/aiopythonik/)\n[![Python Versions](https://img.shields.io/pypi/pyversions/aiopythonik.svg)](https://pypi.org/project/aiopythonik/)\n[![License](https://img.shields.io/pypi/l/aiopythonik.svg)](https://pypi.org/project/aiopythonik/)\n\n## Overview\n\n`aiopythonik` provides asynchronous versions of pythonik functionality\nby wrapping the synchronous operations in a thread pool executor. This\napproach is similar to how `aioboto3` wraps `boto3`, allowing you to use\nasynchronous syntax while maintaining the original library's\ncapabilities.\n\n### Features\n\n- Complete async API for the pythonik library\n- Automatic thread pool management for non-blocking operations\n- Built-in rate limit handling with proactive throttling and\n  configurable retry strategies\n- Extended functionality through patched pythonik methods\n- Support for Python 3.11+\n\n## Installation\n\n### Requirements\n\n- Python 3.11 or higher\n\n```bash\n# Install from PyPI (recommended for most users)\npip install aiopythonik\n```\n\nThe required dependency `nsa-pythonik` will be automatically installed.\n\n### Installing from Source\n\nFor development or to get the latest unreleased changes:\n\n```bash\n# Clone the repository\ngit clone https://bitbucket.org/chesa/aiopythonik.git\ncd aiopythonik\n\n# Install in development mode\npip install -e .\n\n# Install with development dependencies\npip install -e \".[dev]\"\n```\n\n## Quickstart\n\n```python\nimport asyncio\nfrom aiopythonik import AsyncPythonikClient\n\nasync def main():\n    # Initialize the client\n    client = AsyncPythonikClient(\n        app_id=\"your_app_id\",\n        auth_token=\"your_auth_token\",\n        timeout=60,\n        base_url=\"https://app.iconik.io\",\n    )\n\n    try:\n        # Use async methods\n        asset = await client.assets().get(\"asset_id\")\n        print(f\"Asset title: {asset.data.title}\")\n\n        # Get files for the asset\n        files = await client.files().get_asset_files(\"asset_id\")\n        print(f\"Number of files: {len(files.data.files)}\")\n\n        # Search for assets\n        from pythonik.models.search.search_body import SearchBody\n        search_results = await client.search().search(\n            SearchBody(doc_types=[\"assets\"], query=\"title:sample\")\n        )\n        print(f\"Found {len(search_results.data.objects)} assets\")\n\n    finally:\n        # Always close the client when done\n        await client.close()\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n## Using the Context Manager\n\nFor convenience, you can use the async context manager to ensure proper\ncleanup:\n\n```python\nimport asyncio\nfrom aiopythonik import AsyncPythonikClientContext\n\nasync def main():\n    async with AsyncPythonikClientContext(\n        app_id=\"your_app_id\",\n        auth_token=\"your_auth_token\",\n        timeout=60,\n        base_url=\"https://app.iconik.io\",\n    ) as client:\n        # Use async methods\n        asset = await client.assets().get(\"asset_id\")\n        print(f\"Asset title: {asset.data.title}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n## API Coverage\n\n`aiopythonik` provides async wrappers for all pythonik APIs and extends\nfunctionality with some additional methods. Each API from the original\nlibrary is accessible through the corresponding async wrapper:\n\n```python\n# Assets\nasset = await client.assets().get(\"asset_id\")\nassets = await client.assets().fetch(params={\"per_page\": 50})  # Enhanced method\nawait client.assets().delete(\"asset_id\")\n\n# Collections\ncollection = await client.collections().get(\"collection_id\")\ninfo = await client.collections().get_info(\"collection_id\")\ncontents = await client.collections().get_contents(\"collection_id\")\n\n# Files\nfiles = await client.files().get_asset_files(\"asset_id\")\n# Enhanced method with automatic checksum calculation\nfiles_by_checksum = await client.files().get_files_by_checksum(\"d41d8cd98f00b204e9800998ecf8427e\")\n# Or calculate checksum automatically from a file\nfiles_by_file = await client.files().get_files_by_checksum(\"path/to/file.mp4\")\n\n# Metadata\nviews = await client.metadata().get_views()\nview = await client.metadata().get_view(\"view_id\")\nmetadata = await client.metadata().get_asset_metadata(\"asset_id\", \"view_id\")\n\n# Jobs\njob = await client.jobs().get(\"job_id\")\nawait client.jobs().cancel(\"job_id\")\n```\n\n### Automatic Rate Limit Handling\n\nThe library includes built-in handling for API rate limits with both\n**proactive throttling** and **reactive retry logic**:\n\n```python\nfrom aiopythonik import AsyncPythonikClient, RateLimitConfig\n\n# Configure custom rate limiting behavior\nrate_limit_config = RateLimitConfig(\n    max_retries=5,                      # Maximum number of retries for rate-limited requests\n    initial_backoff=1.0,                # Initial backoff in seconds\n    max_backoff=30.0,                   # Maximum backoff in seconds\n    backoff_factor=2.0,                 # Exponential backoff factor\n    jitter=True,                        # Add randomness to backoff times\n    enable_proactive_throttling=True,   # Enable proactive throttling (default: True)\n    proactive_throttling_threshold=0.8, # Start throttling at 80% quota usage\n    max_proactive_delay=5.0             # Maximum proactive delay in seconds\n)\n\nclient = AsyncPythonikClient(\n    app_id=\"your_app_id\",\n    auth_token=\"your_auth_token\",\n    rate_limit_config=rate_limit_config\n)\n\n# Rate-limited requests will automatically be handled with:\n# 1. Proactive throttling - slows down requests before hitting limits\n# 2. Retry logic - handles 429 errors with exponential backoff\n```\n\n#### Proactive Throttling\n\nThe library automatically monitors your API quota usage through\n`RateLimit-Remaining` headers and applies graduated delays **before**\nhitting rate limits:\n\n- **80%+ quota remaining**: No delay (full speed)\n- **30-20% quota remaining**: Light throttling (0.1-0.5s delays)\n- **20-10% quota remaining**: Moderate throttling (0.5-2.0s delays)\n- **<10% quota remaining**: Aggressive throttling (2.0-5.0s delays)\n\nThis prevents 429 errors instead of just reacting to them, resulting in:\n\n- Faster overall operations (no waiting for 5+ second retry delays)\n- More predictable request timing\n- Better resource efficiency\n- Reduced server load\n\n```python\n# Proactive throttling can be disabled if needed\nrate_limit_config = RateLimitConfig(\n    enable_proactive_throttling=False  # Disable proactive throttling\n)\n```\n\n## Advanced Usage\n\n### Concurrent Operations\n\nRunning multiple operations concurrently:\n\n```python\nimport asyncio\nfrom aiopythonik import AsyncPythonikClientContext\n\nasync def main():\n    async with AsyncPythonikClientContext(\n        app_id=\"your_app_id\",\n        auth_token=\"your_auth_token\",\n    ) as client:\n        # Run multiple operations concurrently\n        asset_ids = [\"id1\", \"id2\", \"id3\", \"id4\", \"id5\"]\n\n        tasks = [client.assets().get(asset_id) for asset_id in asset_ids]\n        results = await asyncio.gather(*tasks)\n\n        for i, result in enumerate(results):\n            print(f\"Asset {i+1}: {result.data.title}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n### Custom Base URL\n\nIf you need to use a different API endpoint:\n\n```python\nclient = AsyncPythonikClient(\n    app_id=\"your_app_id\",\n    auth_token=\"your_auth_token\",\n    base_url=\"https://custom.iconik.io\"\n)\n```\n\n### Customizing Thread Pool Size\n\nControl the maximum number of worker threads:\n\n```python\nclient = AsyncPythonikClient(\n    app_id=\"your_app_id\",\n    auth_token=\"your_auth_token\",\n    max_workers=10  # Set maximum number of worker threads\n)\n```\n\n## Rate Limiting Details\n\nThe iconik APIs implement rate limiting to prevent individual users from\nnegatively impacting system performance. By default, the `aiopythonik`\nlibrary includes automatic handling of rate limits using a retry\nstrategy with exponential backoff.\n\nRate limits are enforced per authenticated user and application token:\n\n- 50 requests per second sustained\n- 1000 requests over any 20 second period\n\nThe library uses a **hybrid approach** to handle these limits:\n\n1. **Proactive Throttling**: Monitors `RateLimit-Remaining` headers and\n   gradually slows down requests as you approach the limit, preventing\n   429 errors from occurring\n2. **Reactive Retry Logic**: If 429 errors still occur, automatically\n   retries with exponential backoff\n\nThis combination provides optimal performance - prevention when\npossible, recovery when necessary.\n\nYou can disable automatic rate limit handling if you prefer to manage it\nyourself:\n\n```python\n# Disable all rate limit handling\nclient = AsyncPythonikClient(\n    app_id=\"your_app_id\",\n    auth_token=\"your_auth_token\",\n    disable_rate_limit_handling=True\n)\n\n# Or disable only proactive throttling while keeping retry logic\nrate_limit_config = RateLimitConfig(\n    enable_proactive_throttling=False,  # Disable proactive throttling\n    max_retries=3                       # Keep retry logic\n)\nclient = AsyncPythonikClient(\n    app_id=\"your_app_id\",\n    auth_token=\"your_auth_token\",\n    rate_limit_config=rate_limit_config\n)\n```\n\n## License\n\nMIT\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Asynchronous wrapper for NSA's pythonik client library",
    "version": "2025.7b1",
    "project_urls": {
        "Homepage": "https://chesa.com/",
        "Repository": "https://bitbucket.org/chesa/aiopythonik/"
    },
    "split_keywords": [
        "iconik",
        " api",
        " pythonik",
        " nsa-pythonik",
        " asynchronous"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "002cd3bc298d7afaee990909b4807a0f0eaad08680d1cb71a376127e2baf2e49",
                "md5": "4096fa38081a29c192c65366117aede5",
                "sha256": "42952caa3b124a950694161d4fece81391be44362bd7e7792634aafa54790572"
            },
            "downloads": -1,
            "filename": "aiopythonik-2025.7b1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4096fa38081a29c192c65366117aede5",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 39874,
            "upload_time": "2025-07-30T00:49:05",
            "upload_time_iso_8601": "2025-07-30T00:49:05.966380Z",
            "url": "https://files.pythonhosted.org/packages/00/2c/d3bc298d7afaee990909b4807a0f0eaad08680d1cb71a376127e2baf2e49/aiopythonik-2025.7b1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1d2fa898f8514b3d6910d3dabbfc6f78aec9f2ec0df2312c7a6a1fbe0e3103cd",
                "md5": "3c43163b834f06bb6022b8e79fcca68e",
                "sha256": "15798dee48a88cea46e6fecaef523ae6cb54a892ee250ec01a201a62014328c1"
            },
            "downloads": -1,
            "filename": "aiopythonik-2025.7b1.tar.gz",
            "has_sig": false,
            "md5_digest": "3c43163b834f06bb6022b8e79fcca68e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 35378,
            "upload_time": "2025-07-30T00:49:07",
            "upload_time_iso_8601": "2025-07-30T00:49:07.284029Z",
            "url": "https://files.pythonhosted.org/packages/1d/2f/a898f8514b3d6910d3dabbfc6f78aec9f2ec0df2312c7a6a1fbe0e3103cd/aiopythonik-2025.7b1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-30 00:49:07",
    "github": false,
    "gitlab": false,
    "bitbucket": true,
    "codeberg": false,
    "bitbucket_user": "chesa",
    "bitbucket_project": "aiopythonik",
    "lcname": "aiopythonik"
}
        
Elapsed time: 0.98725s