Skip to main content

Async Python utility library for S3 storage, HTTP client, media/audio processing, JSON/CSV, MongoDB, file management, logging, and configuration

Project description

InoPyUtils

Python Version Version License Development Status

A comprehensive Python utility library designed for modern async workflows, featuring S3-compatible storage, HTTP client, JSON/CSV processing, media and audio handling, file/config management, structured logging, MongoDB access, CivitAI download helpers, and common utility primitives.


Important Notice

Active Development — This library is under active development and evolving rapidly. APIs may change without prior notice.

Beta Status — Currently in beta. While functional, thorough testing is recommended before production use.

Contributions Welcome — Feedback, issue reports, and pull requests are encouraged.


Installation

PyPI (Recommended)

pip install inopyutils

Development

git clone https://github.com/nobandegani/InoPyUtils.git
cd InoPyUtils
pip install -e .

Requirements

  • Python 3.9+
  • FFmpeg (optional) — required for InoMediaHelper video conversion and InoAudioHelper audio transcoding

Helpers

S3-Compatible Storage (InoS3Helper)

Async S3 client supporting AWS S3, Backblaze B2, DigitalOcean Spaces, Wasabi, MinIO, and other S3-compatible services. Features retry with exponential backoff, folder upload/download/sync, presigned URLs, and file verification.

import asyncio
from inopyutils import InoS3Helper

async def main():
    async with InoS3Helper(
        aws_access_key_id="your_key_id",
        aws_secret_access_key="your_secret_key",
        endpoint_url="https://s3.us-west-004.backblazeb2.com",
        region_name="us-west-004",
        bucket_name="your-bucket",
        retries=5,
    ) as s3:
        # Upload & download (overwrite=False by default, skips if file matches)
        await s3.upload_file("local.txt", "remote/path/file.txt")
        await s3.download_file("remote/path/file.txt", "downloaded.txt")
        await s3.download_file("remote/path/file.txt", "downloaded.txt", overwrite=True)  # force re-download

        # Check existence, list objects
        exists = await s3.object_exists("remote/path/file.txt")
        objects = await s3.list_objects(prefix="remote/path/")

        # Folder operations (overwrite=False by default, skips unchanged files)
        await s3.upload_folder(s3_folder_key="remote/folder/", local_folder_path="local_folder/")
        await s3.download_folder(s3_folder_key="remote/folder/", local_folder_path="local_download/")
        await s3.sync_folder(s3_key="remote/folder/", local_folder_path="local_sync/")

        # Verify files match between local and S3
        await s3.verify_file("local.txt", "remote/path/file.txt", use_md5=True)
        await s3.verify_folder_sync(s3_folder_key="remote/folder/", local_folder_path="local_folder/")

        # Quick text/bytes
        await s3.put_text("hello", "remote/hello.txt")
        res = await s3.get_text("remote/hello.txt")
        print(res["text"])

        # Presigned download link
        link = await s3.get_download_link("remote/path/file.txt", expires_in=3600)
        print(link["url"])

asyncio.run(main())

HTTP Client (InoHttpHelper)

Async HTTP client built on aiohttp with configurable timeouts, retries with exponential backoff, base URL support, auth, and file downloads with resume and multi-connection support.

import asyncio
from inopyutils import InoHttpHelper

async def main():
    async with InoHttpHelper(
        base_url="https://api.example.com",
        timeout_total=30.0,
        retries=3,
        backoff_factor=0.7,
        default_headers={"User-Agent": "InoPyUtils/1.7.7"},
    ) as client:
        # GET JSON
        resp = await client.get("/users/42", json=True)

        # POST JSON
        resp = await client.post(
            "/items",
            json={"name": "Widget", "price": 9.99},
            json_response=True,
        )

        # Download file with resume support
        resp = await client.download(
            "https://example.com/file.zip",
            dest_path="downloads/",
            resume=True,
            connection=4,  # multi-connection parallel download
        )

asyncio.run(main())

All verb methods (get, post, put, delete, patch) return a dict with: success, msg, status_code, headers, data, url, method, attempts.


JSON Processing (InoJsonHelper)

JSON manipulation toolkit with sync and async file I/O, deep merge, flatten/unflatten, dot-path access, comparison, filtering, and search.

import asyncio
from inopyutils import InoJsonHelper

# String/Dict conversion
result = InoJsonHelper.string_to_dict('{"key": "value"}')
data = result["data"] if result["success"] else {}

# Deep merge
merged = InoJsonHelper.deep_merge({"a": 1, "nested": {"x": 10}}, {"b": 2, "nested": {"y": 20}})

# Flatten / unflatten
flat = InoJsonHelper.flatten({"a": {"b": {"c": 1}}})      # {"a.b.c": 1}
nested = InoJsonHelper.unflatten({"a.b.c": 1})             # {"a": {"b": {"c": 1}}}

# Safe dot-path access
value = InoJsonHelper.safe_get(data, "user.profile.name", default="Unknown")
InoJsonHelper.safe_set(data, "user.profile.age", 25)

# Compare two structures
diff = InoJsonHelper.compare({"a": 1}, {"a": 2})

# Async file I/O
async def save_and_load():
    await InoJsonHelper.save_json_as_json_async({"config": "data"}, "config.json")
    loaded = await InoJsonHelper.read_json_from_file_async("config.json")
    print(loaded["data"])

asyncio.run(save_and_load())

CSV Utilities (InoCsvHelper)

Async CSV file read/write with in-memory helpers for headers, rows, columns, and sorting. Data is always list[dict].

import asyncio
from inopyutils import InoCsvHelper

rows = [{"id": 2, "name": "Bob"}, {"id": 1, "name": "Alice"}]

async def main():
    await InoCsvHelper.save_csv_to_file_async(rows, "people.csv")
    res = await InoCsvHelper.read_csv_from_file_async("people.csv")
    print(res["data"]["headers"], len(res["data"]["rows"]))

    # In-memory utilities
    headers = InoCsvHelper.get_headers(rows)
    first = InoCsvHelper.get_row(rows, 0)
    ids = InoCsvHelper.get_column(rows, "id")
    sorted_rows = InoCsvHelper.sort_rows(rows, by=["name", "id"])

asyncio.run(main())

File Management (InoFileHelper)

File and folder operations: zip/unzip, copy with rename, move, remove, count, media validation, string-to-file, SHA-256 hashing.

import asyncio
from inopyutils import InoFileHelper
from pathlib import Path

async def main():
    # ZIP compression
    await InoFileHelper.zip(
        to_zip=Path("source_folder"),
        path_to_save=Path("archives"),
        zip_file_name="backup.zip",
        compression_level=6,
    )

    # Copy and rename files
    await InoFileHelper.copy_files(
        from_path=Path("source"),
        to_path=Path("processed"),
        rename_files=True,
        prefix_name="File",
    )

    # File utilities
    count = await InoFileHelper.count_files(Path("folder"), recursive=True)
    last = InoFileHelper.get_last_file(Path("folder"))
    next_name = InoFileHelper.increment_batch_name("Batch_001")  # "Batch_002"

    # SHA-256 hash
    sha = await InoFileHelper.get_file_hash_sha_256(Path("file.bin"))
    print(sha["sha"])

asyncio.run(main())

Media Processing (InoMediaHelper)

Image validation/conversion via Pillow (HEIF/HEIC supported). Video conversion via FFmpeg with resolution and FPS capping.

import asyncio
from inopyutils import InoMediaHelper
from pathlib import Path

async def main():
    # Image: fix EXIF rotation, resize, convert to JPEG
    res = await InoMediaHelper.image_validate_pillow(
        input_path=Path("photo.heic"),
        output_path=Path("converted.jpg"),
        max_res=2048,
        jpg_quality=85,
    )

    # Video: convert to MP4, cap resolution and FPS
    res = await InoMediaHelper.video_convert_ffmpeg(
        input_path=Path("input.mov"),
        output_path=Path("optimized.mp4"),
        change_res=True, max_res=1920,
        change_fps=True, max_fps=30,
    )

    # Extract a frame from video
    res = await InoMediaHelper.video_extract_frame(
        input_path=Path("video.mp4"),
        output_path=Path("frame.jpg"),
    )

asyncio.run(main())

Audio Processing (InoAudioHelper)

Audio utilities for raw PCM: transcode to OGG/Opus or WAV, decode any format to PCM, chunk for streaming, estimate duration, generate silence. Requires FFmpeg.

import asyncio
from inopyutils import InoAudioHelper

async def main():
    with open("audio.ogg", "rb") as f:
        ogg_bytes = f.read()

    # Decode to raw PCM
    dec = await InoAudioHelper.audio_to_raw_pcm(ogg_bytes, rate=16000, channel=1)
    pcm = dec["data"]

    # Transcode PCM to OGG/Opus
    enc = await InoAudioHelper.transcode_raw_pcm(
        pcm, output="ogg", codec="libopus", rate=16000, channel=1,
    )

    # Chunk for streaming
    chunks = await InoAudioHelper.chunks_raw_pcm(pcm, chunk_size=3200)

    # Utilities (no FFmpeg needed)
    seconds = InoAudioHelper.get_audio_duration_from_text("Hello world", wpm=160.0)
    silence = InoAudioHelper.get_empty_audio_pcm_bytes(duration=2, rate=16000, channel=1)

asyncio.run(main())

Thumbnail Generation (InoThumbnailHelper)

Generate square JPEG thumbnails at multiple sizes. Center-crop or pad with blurred background. Strips EXIF metadata.

import asyncio
from pathlib import Path
from inopyutils import InoThumbnailHelper

# Sync
res = InoThumbnailHelper.image_generate_square_thumbnails(
    image_path=Path("photo.jpg"),
    output_dir=Path("thumbnails/"),
    sizes=(256, 512, 1024),
    quality=85,
    crop=False,  # True: center-crop, False: blurred background padding
)

# Async
async def main():
    res = await InoThumbnailHelper.image_generate_square_thumbnails_async(
        image_path=Path("photo.heic"),
        output_dir=Path("thumbnails/"),
        sizes=(256, 768),
        crop=True,
    )

asyncio.run(main())

MongoDB Helper (InoMongoHelper)

Async MongoDB helper wrapping Motor. Initialize once, use everywhere. Auto-converts _id between str and ObjectId.

import asyncio
from inopyutils import InoMongoHelper

mongo = InoMongoHelper()

async def main():
    await mongo.connect(
        uri="mongodb://localhost:27017",
        db_name="mydb",
        check_connection=True,
    )

    # CRUD
    res = await mongo.insert_one("users", {"name": "Ann"})
    user = await mongo.find_one("users", {"_id": res["inserted_id"]})
    await mongo.update_one("users", {"_id": res["inserted_id"]}, {"$set": {"name": "Anna"}})
    await mongo.delete_one("users", {"_id": res["inserted_id"]})

    await mongo.close()

asyncio.run(main())

CivitAI Integration (InoCivitHelper)

Async helper for fetching CivitAI model metadata and downloading model files with SHA-256 verification and multi-connection resume support.

import asyncio
from pathlib import Path
from inopyutils import InoCivitHelper

async def main():
    civit = InoCivitHelper(token="your_civitai_token")
    try:
        res = await civit.download_model(
            model_path=Path("./models"),
            model_id=123,
            model_version=456,
            file_id=0,
            chunk_size=8,
            download_connections=6,
        )
        print(res)
    finally:
        await civit.close()

asyncio.run(main())

Token can also be set via CIVITAI_TOKEN environment variable.


OpenAI-Compatible Chat (InoOpenAIHelper)

Async chat completions client using the OpenAI SDK. Works with any OpenAI-compatible endpoint (RunPod, vLLM, Ollama, OpenAI, etc.). Supports vision/image input.

import asyncio
from inopyutils import InoOpenAIHelper

async def main():
    # Text chat
    res = await InoOpenAIHelper.chat_completions(
        api_key="your_api_key",
        base_url="https://api.runpod.ai/v2/YOUR_ENDPOINT/openai/v1",
        model="qwen3-vl-32b",
        user_prompt="What is quantum computing?",
        system_prompt="You are a helpful assistant. Reply concisely.",
        temperature=0.7,
        max_tokens=256,
    )
    if res["success"]:
        print(res["response"])

    # Vision with image
    res = await InoOpenAIHelper.chat_completions(
        api_key="your_api_key",
        base_url="https://api.runpod.ai/v2/YOUR_ENDPOINT/openai/v1",
        model="qwen3-vl-32b",
        user_prompt="Describe this image.",
        image="https://example.com/photo.jpg",  # URL or data:image/jpeg;base64,...
    )

asyncio.run(main())

RunPod Serverless vLLM (InoRunpodHelper)

Async helper for RunPod serverless vLLM endpoints via the runsync API. Uses the OpenAI-compatible route for proper vision/multimodal support.

import asyncio
from inopyutils import InoRunpodHelper

async def main():
    # Text chat
    res = await InoRunpodHelper.serverless_vllm_runsync(
        url="https://api.runpod.ai/v2/YOUR_ENDPOINT/runsync",
        api_key="your_runpod_api_key",
        model="qwen3-vl-32b",
        user_prompt="List 3 benefits of drinking water.",
        system_prompt="You are a helpful assistant.",
        temperature=0.3,
        max_tokens=256,
    )
    if res["success"]:
        print(res["response"])
        print(f"Execution time: {res['execution_time']}ms")

    # Vision with image
    res = await InoRunpodHelper.serverless_vllm_runsync(
        url="https://api.runpod.ai/v2/YOUR_ENDPOINT/runsync",
        api_key="your_runpod_api_key",
        model="qwen3-vl-32b",
        user_prompt="What do you see in this image?",
        image="data:image/jpeg;base64,/9j/4AAQ...",
    )

asyncio.run(main())

Configuration Management (InoConfigHelper)

INI config file manager with type-safe access, fallbacks, and sync/async save.

import asyncio
from inopyutils import InoConfigHelper

config = InoConfigHelper("config/app.ini")

# Read with type safety
url = config.get("database", "url", fallback="sqlite:///default.db")
debug = config.get_bool("app", "debug", fallback=False)

# Write (sync)
config.set("api", "endpoint", "https://api.prod.com")

# Write (async)
async def main():
    await config.set_async("features", "cache_enabled", True)
    await config.save_async()

asyncio.run(main())

Structured Logging (InoLogHelper)

Async JSONL logger with automatic file rotation by size. Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL.

import asyncio
from inopyutils import InoLogHelper, LogType
from pathlib import Path

async def main():
    logger = await InoLogHelper.create(Path("logs"), "MyApp")

    await logger.info(
        msg="User login",
        log_data={"user_id": 123, "ip": "192.168.1.1"},
        source="auth",
    )

    await logger.error(
        msg="Request failed",
        log_data={"status": 500, "endpoint": "/api/users"},
        source="api",
    )

asyncio.run(main())

Output files: logs/MyApp_00001.inolog (rotates at 10MB by default).


Photo Metadata (InoPhotoMetadata)

Dataclass for EXIF-like photo metadata with pre-filled profiles (iphone, samsung).

from inopyutils import InoPhotoMetadata

meta = InoPhotoMetadata(profile="iphone")
meta.iso_speed = 100
meta.gps_latitude = 37.7749
meta.gps_longitude = -122.4194

Utility Helpers (ino_ok, ino_err, ino_is_err, InoUtilHelper)

Result envelope primitives used by all helpers, plus common ID/hash utilities.

from inopyutils import ino_ok, ino_err, ino_is_err, InoUtilHelper

res = ino_ok("done", value=42)
print(res["success"], res["value"])  # True 42

if ino_is_err(ino_err("failed")):
    print("error path")

digest = InoUtilHelper.hash_string("hello", algo="sha256", length=16)
uid = InoUtilHelper.generate_unique_id_by_time()
stamp = InoUtilHelper.get_date_time_utc_base64()

Dependencies

Package Purpose
pillow Image processing
pillow_heif HEIF/HEIC format support
aioboto3 Async S3 operations
aiofiles Async file I/O
aiohttp Async HTTP client
botocore / boto3 AWS SDK
motor Async MongoDB driver
openai OpenAI-compatible API client
inocloudreve Cloud storage integration

Optional: FFmpeg — required for InoMediaHelper video conversion and InoAudioHelper audio transcoding.


Project Info

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

inopyutils-1.9.1.tar.gz (77.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

inopyutils-1.9.1-py3-none-any.whl (77.4 kB view details)

Uploaded Python 3

File details

Details for the file inopyutils-1.9.1.tar.gz.

File metadata

  • Download URL: inopyutils-1.9.1.tar.gz
  • Upload date:
  • Size: 77.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for inopyutils-1.9.1.tar.gz
Algorithm Hash digest
SHA256 17447fe6539323fee0b805b33fdf46ceea8c8a0e9c573aeb5832710744a644b1
MD5 c61ed11e94d5d179418288a5fe170c76
BLAKE2b-256 f7aa4c4ee1ac924574c33106182ea7dc177304cd78d605b72c6af7f6c7771ac2

See more details on using hashes here.

File details

Details for the file inopyutils-1.9.1-py3-none-any.whl.

File metadata

  • Download URL: inopyutils-1.9.1-py3-none-any.whl
  • Upload date:
  • Size: 77.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for inopyutils-1.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3b1469b7b4de23ac3f12388ad89b10fe747b7fa9f1909eea435cdf298ed63af4
MD5 e79146318bc29879ac2466121ac42673
BLAKE2b-256 6216b527b1033add4f271bc887e7b4b9ca04e5d548487881a5a26468bcb16c2d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page