Skip to main content

PyPI version License: MIT Downloads LinkedIn

hashcounter

hashcounter is a tiny async Redis helper: per-string counter with a sliding TTL.
Input string → SHA-256 → key "{prefix}:{hash}" → atomic INCR + EXPIRE in one transaction.

Installation

pip install hashcounter

Requires redis>=5.0.0 and a running Redis server.

Quick start

import asyncio
from hashcounter import bump_string_counter

async def main() -> None:
    count = await bump_string_counter(
        "world_debug_test_v234",
        redis_url="redis://localhost:6379/0",
        key_prefix="llm7:seen",
        ttl_seconds=600,  # 10 minutes
    )
    print(count)  # 1 on first call, then 2, 3, ...

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

FastAPI (shared Redis client)

from __future__ import annotations

import redis.asyncio as redis
from fastapi import FastAPI
from hashcounter import bump_string_counter

app = FastAPI()
r = redis.from_url("redis://localhost:6379/0", decode_responses=False)

@app.on_event("shutdown")
async def _shutdown() -> None:
    await r.aclose()

@app.post("/hit")
async def hit(s: str) -> dict[str, int]:
    count = await bump_string_counter(
        s,
        redis_url="redis://localhost:6379/0",
        key_prefix="llm7:seen",
        ttl_seconds=600,
        client=r,  # reuse connection pool
    )
    return {"count": count}

Behaviour

  • Key: f"{key_prefix}:{sha256(value)}".
  • Atomicity: INCR and EXPIRE run in a single MULTI/EXEC transaction.
  • Sliding TTL: TTL resets to ttl_seconds on every call.
  • First call: creates the key with value 1.
  • Return: current counter value (int).
  • Validation: raises ValueError if ttl_seconds <= 0.

API

async def bump_string_counter(
    value: str,
    *,
    redis_url: str,
    key_prefix: str,
    ttl_seconds: int = 600,
    client: Optional[redis.Redis] = None,
) -> int:
    """Increment the counter and refresh TTL. Return the current value."""

Parameters:

  • value: arbitrary string to count.
  • redis_url: Redis connection URL (ignored if client is provided).
  • key_prefix: namespace prefix for keys.
  • ttl_seconds: key time-to-live (seconds), refreshed on each call.
  • client: existing redis.asyncio.Redis instance (recommended in services).

Use cases

  • Prompt/request deduplication and anti-spam windows.
  • Per-key rate limiting by arbitrary features (prompt hash, user token, IP).
  • Telemetry: “seen count in the last N minutes”.

Contributing

Issues and PRs are welcome: https://github.com/chigwell/hashcounter/issues.

License

MIT © Eugene Evstafev

Metadata

Release files for hashcounter 2025.8.241412

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hashcounter 2025.8.241412
File Size Uploaded Provenance Actions
hashcounter-2025.8.241412.tar.gz 4.4 kB Without provenance Details for hashcounter-2025.8.241412.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for hashcounter 2025.8.241412
File Interpreter ABI Platform Actions
hashcounter-2025.8.241412-py3-none-any.whl Python 3 none any Details for hashcounter-2025.8.241412-py3-none-any.whl

Total release size: 9.1 kB

Release files / hashcounter-2025.8.241412.tar.gz

Download URL hashcounter-2025.8.241412.tar.gz
Size 4.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f662c5e00e9519f5e8b26cd76ae65a789fbd80dcd0cc58169df1f6fedf0a9484
BLAKE2b-256 checksum
How to use checksums
910a33d9e974303dfa12e0bf45ad5f4a5c95a28d7aed72d83e1209b10526373e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.11

Release files / hashcounter-2025.8.241412-py3-none-any.whl

Download URL hashcounter-2025.8.241412-py3-none-any.whl
Size 4.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
10b9800a9c523c9f87be0b9d999a8fd934418b23dff4275674cb3d56c7d7451e
BLAKE2b-256 checksum
How to use checksums
cf5c9e4f9c5d650034d7f93ccf18737378052903ddc47b73ea1b1ca50350ff9b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.11

Security for hashcounter 2025.8.241412

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page