Metadata-Version: 2.4
Name: fluxrate
Version: 0.3.0
Summary: Lightweight, thread-safe rate limiting for Python — token bucket, sliding window, fixed window, leaky bucket
Author-email: Ravi Teja Prabhala Venkata <raviteja.prabhala@gmail.com>
License-Expression: MIT
Keywords: rate-limit,rate-limiter,throttle,token-bucket,sliding-window,api,middleware
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
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 :: System :: Networking
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"

<p align="center">
  <strong>fluxcontrol</strong><br>
  Lightweight, thread-safe rate limiting for Python
</p>

<p align="center">
  <img src="https://img.shields.io/badge/version-0.1.0-blue" alt="Version">
  <img src="https://img.shields.io/badge/python-3.10%2B-blue" alt="Python 3.10+">
  <img src="https://img.shields.io/badge/license-MIT-green" alt="License">
  <img src="https://img.shields.io/badge/dependencies-zero-success" alt="Zero Dependencies">
  <img src="https://img.shields.io/badge/coverage-100%25-brightgreen" alt="Coverage">
</p>

<p align="center">
  <strong>Zero dependencies. Four algorithms. One API.</strong>
</p>

---

## Why fluxcontrol?

Rate limiting is a fundamental building block of distributed systems — yet the Python ecosystem forces developers to choose between **bloated frameworks** and **single-algorithm libraries**.

- **slowapi** bundles Flask/Starlette dependencies and only implements fixed-window counters.
- **ratelimit** provides a single decorator with one algorithm and no per-key support.
- **limits** (the library behind flask-limiter) is well-designed but pulls in storage backend dependencies and is tightly coupled to web frameworks.
- **flask-limiter** only works with Flask and delegates to `limits`.

**fluxcontrol** fills a gap that no existing package addresses: a single, dependency-free library that provides **four production-proven rate-limiting algorithms** through a **unified API** — usable as a decorator, context manager, or manual guard, without any framework lock-in.

## Quick Start

```bash
pip install fluxcontrol
```

```python
from fluxcontrol import RateLimiter

# Decorator
@RateLimiter(calls=10, period=60)
def api_call():
    return do_work()

# Manual check
limiter = RateLimiter(calls=100, period=60)
if limiter.allow("user_123"):
    process_request()

# Context manager
with limiter.acquire("user_123", timeout=5):
    call_external_api()
```

## Use Cases

| Use Case | Recommended Algorithm | Why |
|----------|----------------------|-----|
| **API Rate Limiting** | Token Bucket | Allows legitimate bursts while enforcing sustained rate |
| **DDoS Protection** | Sliding Window | Precise control with no boundary-exploitable windows |
| **Resource Throttling** | Leaky Bucket | Smooths output to a fixed rate, prevents resource spikes |
| **Queue Management** | Leaky Bucket | Models queue drain rate naturally |
| **Per-User Limits** | Any (with key_func) | `key_func` routes each user to an independent bucket |
| **Billing Enforcement** | Sliding Window | Accurate accounting across window boundaries |
| **Simple Capping** | Fixed Window | Minimal overhead when precision isn't critical |

## Algorithm Comparison

Choosing the right algorithm depends on your traffic pattern and precision requirements:

### Token Bucket

The workhorse of rate limiting. Tokens are added at a fixed rate and consumed per request. Accumulated tokens allow **bursts** up to the bucket capacity, then requests are rejected until tokens refill.

**When to use:** APIs with variable traffic, user-facing services that need burst tolerance, any scenario where you want to be "generous but bounded."

### Sliding Window

Tracks request timestamps in a rolling window. Unlike fixed windows, there are **no boundary artifacts** — a window starting at 12:59 and one at 13:00 are part of the same continuous time span.

**When to use:** Billing or quota enforcement where precision matters, compliance-sensitive rate limits, preventing window-boundary attacks.

### Fixed Window

Divides time into discrete buckets (e.g., 60-second windows starting at :00 seconds). Counts requests per bucket. Simple, fast, but susceptible to **boundary bursts** — two requests at 12:59:59 and 13:00:01 each land in different windows.

**When to use:** Prototyping, internal services where approximate limits suffice, high-throughput scenarios where minimal overhead is critical.

### Leaky Bucket

Models a queue with a fixed drain rate. Requests enter a queue; the queue drains at a constant rate regardless of inflow. This **smooths traffic** rather than rejecting bursts.

**When to use:** Output to external APIs with strict rate limits, database write throttling, any downstream system that can't handle bursty input.

```
           Token Bucket              Leaky Bucket
          ┌──────────┐              ┌──────────┐
 Tokens   │ ▓▓▓▓░░░░ │  Requests   │ ▓▓▓░░░░░ │  Queue
 refill → │          │  ──────────→ │          │ ──→ drain
 at rate  │ capacity │             │ capacity │  at rate
          └──────────┘              └──────────┘
          Allows bursts             Smooths output
```

## Features

- 🧵 **Thread-safe** by default — all algorithms use internal locking
- 🔑 **Per-key limiting** — per user, IP, API key, or any custom key function
- 🎯 **Three usage modes** — decorator, context manager, manual guard
- 📊 **Stats & monitoring** — built-in usage statistics per key
- ⏱️ **Retry-After** — standard HTTP `Retry-After` header values out of the box
- 🚫 **Zero dependencies** — pure Python, no framework coupling
- 📦 **Four algorithms** — token bucket, sliding window, fixed window, leaky bucket

## Comparison with Existing Solutions

| Feature | fluxcontrol | slowapi | ratelimit | limits | flask-limiter |
|---------|:-----------:|:-------:|:---------:|:------:|:-------------:|
| Token Bucket | ✅ | ❌ | ❌ | ✅ | ✅ |
| Sliding Window | ✅ | ❌ | ❌ | ✅ | ✅ |
| Fixed Window | ✅ | ✅ | ✅ | ✅ | ✅ |
| Leaky Bucket | ✅ | ❌ | ❌ | ✅ | ❌ |
| Zero Dependencies | ✅ | ❌ | ✅ | ❌ | ❌ |
| Per-Key Limiting | ✅ | ✅ | ❌ | ✅ | ✅ |
| Context Manager | ✅ | ❌ | ❌ | ❌ | ❌ |
| Built-in Stats | ✅ | ❌ | ❌ | ❌ | ✅ |
| Framework Agnostic | ✅ | ❌ | ✅ | ✅ | ❌ |
| Thread-Safe | ✅ | ✅ | ❌ | ✅ | ✅ |

## Design Philosophy

1. **Unified API, Multiple Strategies** — one `RateLimiter` class, four algorithms. Switch strategies by changing a string argument — no rewrites, no adapter pattern ceremony.

2. **Zero-Dependency by Default** — no Redis, no Flask, no Celery. Import and go. Add storage backends only when you need distributed coordination.

3. **Framework Agnostic** — fluxcontrol doesn't know or care whether you're building a Flask API, a FastAPI service, a CLI tool, or a background worker. Rate limiting is orthogonal to your framework choice.

4. **Safety First** — every public method is thread-safe. No footguns. `RateLimitExceeded` exceptions carry `retry_after` values so you can build compliant HTTP responses without extra math.

5. **Progressive Complexity** — start with `@RateLimiter(calls=100, period=60)`. Add per-key limiting. Switch algorithms. Plug in custom key functions. Each layer of complexity is opt-in.

## API Reference

### `RateLimiter(calls, period, algorithm="token_bucket", ...)`

High-level API supporting all four algorithms.

```python
RateLimiter(
    calls=100,           # max calls per period
    period=60,           # time window in seconds
    algorithm="token_bucket",  # "token_bucket", "sliding_window", "fixed_window", "leaky_bucket"
    key_func=lambda user: user,  # per-key rate limiting
    burst=150,           # burst capacity (token bucket)
    raise_on_limit=True, # raise exception or return None
)
```

### Low-Level APIs

```python
from fluxcontrol import TokenBucket, SlidingWindow, FixedWindow, LeakyBucket

# Token Bucket — allows bursts up to capacity
tb = TokenBucket(rate=10, capacity=50)
tb.allow()          # consume 1 token
tb.consume(5)       # consume 5 tokens
tb.retry_after()    # seconds until next available
tb.available        # current token count
tb.stats()          # usage statistics

# Sliding Window — precise, no boundary burst
sw = SlidingWindow(max_calls=100, window_seconds=60)
sw.allow("user_id")
sw.count            # calls in current window
sw.retry_after("user_id")

# Fixed Window — simple, fast
fw = FixedWindow(max_calls=100, window_seconds=60)
fw.allow("user_id")

# Leaky Bucket — smooth output rate
lb = LeakyBucket(rate=10, capacity=50)
lb.allow("user_id")
lb.level            # current queue level
```

### Exceptions

```python
from fluxcontrol.exceptions import RateLimitExceeded, TimeoutExceeded

try:
    rate_limited_func()
except RateLimitExceeded as e:
    retry_after = e.retry_after  # seconds to wait
```

## License

MIT © [Ravi Teja Prabhala Venkata](https://github.com/ravitejapv)
