A small pipeline-aware rate limiting libray for data engineering workflows
Project description
andor
andor is a lightweight Python pipeline utility for running functions over a list of inputs with optional batching and throttling.
It is designed for workflows where you need to process many records while controlling request pacing, such as:
- API ingestion jobs
- data enrichment pipelines
- bulk transformation scripts
Features
- Chainable pipeline configuration
- Batch-based execution
- Per-item randomized delay (throttling)
- Per-batch randomized pause
- Tuple input unpacking for multi-argument functions
- Built-in error handling that skips failed items and continues
Installation
Install from source in editable mode:
pip install -e .
Or install dependencies only:
pip install -r requirements.txt
Quick Start
from andor.pipeline import Pipeline
data = [1, 2, 3, 4]
def square(x):
return x * x
result = Pipeline(source=data).run(square)
print(result)
# [1, 4, 9, 16]
Core Concepts
1) Source Data
The pipeline takes a list-like source and iterates through it.
Each item can be:
- a single value (passed as one argument)
- a tuple (unpacked into multiple function arguments)
2) Batching
Use .batch(size=...) to process inputs in chunks.
from andor.pipeline import Pipeline
data = ["a", "b", "c", "d", "e"]
def process(value):
return value.upper()
result = (
Pipeline(source=data)
.batch(size=2)
.run(process)
)
print(result)
# ['A', 'B', 'C', 'D', 'E']
When batching is enabled, progress output is printed for each batch.
3) Throttling
Use .throttle(delay=(min_seconds, max_seconds), pause=(min_seconds, max_seconds)) to slow processing.
delay: sleep between each processed itempause: sleep between batches
from andor.pipeline import Pipeline
items = [1, 2, 3, 4, 5, 6]
def identity(x):
return x
result = (
Pipeline(source=items)
.batch(size=3)
.throttle(delay=(0.2, 0.5), pause=(1.0, 2.0))
.run(identity)
)
In this example:
- each item waits a random delay between
0.2and0.5seconds - each completed batch waits a random pause between
1.0and2.0seconds
Tuple Unpacking Example
If your source contains tuples, they are expanded into function arguments automatically.
from andor.pipeline import Pipeline
pairs = [(2, 3), (4, 5), (10, 20)]
def add(a, b):
return a + b
result = Pipeline(source=pairs).run(add)
print(result)
# [5, 9, 30]
Error Handling Behavior
If a function call raises an exception, the pipeline:
- prints an error message with the item index
- skips the failed item
- continues processing the rest of the data
This allows long-running jobs to complete even when some records fail.
from andor.pipeline import Pipeline
data = [10, 5, 0, 2]
def divide_100_by(x):
return 100 / x
result = Pipeline(source=data).run(divide_100_by)
print(result)
# [10.0, 20.0, 50.0]
# (division by zero is logged and skipped)
Example
Before:
def run_funds_data_pipeline():
print(f"--- STARTING FUNDS ANALYSIS (Catalog: {CATALOG_NAME}) ---", flush=True)
processed_data = []
fund_items = list(FUND_LIST.items())
for i, (ticker, name) in enumerate(fund_items):
try:
record = analyze_fund(ticker, name)
if record:
processed_data.append(record)
except Exception as e:
print(f"Error analyzing {ticker}: {e}")
delay = random.uniform(REQUEST_DELAY_MIN, REQUEST_DELAY_MAX)
print(f" Sleeping {delay:.1f}s...", flush=True)
time.sleep(delay)
if (i + 1) % BATCH_SIZE == 0 and (i + 1) < len(fund_items):
batch_pause = random.uniform(BATCH_PAUSE_MIN, BATCH_PAUSE_MAX)
print(f"\n--- Batch of {BATCH_SIZE} complete. Pausing {batch_pause:.1f}s ---\n", flush=True)
time.sleep(batch_pause)
if not processed_data:
print("No data collected.")
return
The workflow now looks like this:
fund_items = list(FUND_LIST.items())
pipeline = Pipeline(source=fund_items)
pipeline.batch(size=20)
pipeline.throttle(delay=(1.5, 4), pause=(1.5, 4))
results = pipeline.run(analyze_fund)
API Reference
Pipeline(source)
Creates a new pipeline instance.
source: iterable collection of items to process
Pipeline.batch(size)
Sets batch size and returns the same Pipeline instance.
size(int): number of items per batch
Pipeline.throttle(delay=None, pause=None)
Configures randomized wait times and returns the same Pipeline instance.
delay(tuple[float, float] | None): per-item sleep rangepause(tuple[float, float] | None): per-batch sleep range
Pipeline.run(func)
Executes the pipeline and returns a list of successful results.
func: callable to apply to each item
Practical Pattern for API Workloads
import requests
from andor.pipeline import Pipeline
ids = [101, 102, 103, 104, 105]
def fetch_record(record_id):
response = requests.get(f"https://api.example.com/items/{record_id}", timeout=10)
response.raise_for_status()
return response.json()
records = (
Pipeline(source=ids)
.batch(size=2)
.throttle(delay=(0.3, 0.7), pause=(1.5, 2.5))
.run(fetch_record)
)
Development
Run tests with:
pytest
License
This project is licensed under the terms in LICENSE.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file andor_data-0.1.0.tar.gz.
File metadata
- Download URL: andor_data-0.1.0.tar.gz
- Upload date:
- Size: 5.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9cea1ed6cf1487e8084a6cc3ef48c963472252ce2d350516b339cb8307cca65
|
|
| MD5 |
908a44f7ea9d66efe0c5bc90f0577319
|
|
| BLAKE2b-256 |
67deb4f8120ef14308a5ed9bac0c01283907e35cc96115bcefc9f05dbde7ae39
|
File details
Details for the file andor_data-0.1.0-py3-none-any.whl.
File metadata
- Download URL: andor_data-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7419dc585085ce7fec134bf1fbbe23baff00c275480cd7ff1fa841e4357d586
|
|
| MD5 |
92d38f1b9466dc160371dac30cad3fb9
|
|
| BLAKE2b-256 |
36259966420d8a21eb152d84d61d2fa3c1f806b9cbd514244cca0fa281ecef3a
|