Helpers¶
The helpers
module provides utility functions, decorators, interceptors, and metaclasses to support common development
tasks and patterns.
Overview¶
The helpers
module provides utility functions and classes to simplify common development tasks.
Installation¶
This module is included in the base ArchiPy installation:
For development features:
Source Code¶
📁 Location: archipy/helpers/
API Stability¶
Component | Status | Notes |
---|---|---|
Decorators | 🟢 Stable | Production-ready |
Utils | 🟢 Stable | Production-ready |
Interceptors | 🟡 Beta | API may change |
Metaclasses | 🟢 Stable | Production-ready |
Submodules¶
Utils¶
See Utils Documentation for full documentation.
General utility functions for common operations:
- String manipulation
- Date and time handling
- Error utilities
- File operations
- Password utilities
- JWT token handling
- TOTP generation
Decorators¶
See Decorators Documentation for full documentation.
Function and class decorators for:
- Method deprecation
- Class deprecation
- Timing operations
- Retry logic
Interceptors¶
See Interceptors Documentation for full documentation.
Classes for cross-cutting concerns:
- Logging
- Performance monitoring
- Request/response tracking
Overview¶
The helpers module offers utilities, decorators, and interceptors to enhance productivity and simplify common development tasks, such as retry logic, rate limiting, and tracing.
See Examples: Examples Helpers
Decorators¶
Tip: See Examples Helpers Decorators for practical examples of decorators.
Retry Decorator¶
The retry decorator provides a mechanism to automatically retry failed operations with configurable backoff strategies.
from archipy.helpers.decorators.retry import retry
@retry(max_attempts=3, delay=1, backoff=2)
def risky_operation():
# Operation that might fail
result = some_unreliable_function()
return result
# Will retry up to 3 times with exponential backoff
result = risky_operation()
archipy.helpers.decorators.retry.retry_decorator(max_retries=3, delay=1, retry_on=None, ignore=None, resource_type=None, lang=LanguageType.FA)
¶
A decorator that retries a function when it raises an exception.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
max_retries
|
int
|
The maximum number of retry attempts. Defaults to 3. |
3
|
delay
|
float
|
The delay (in seconds) between retries. Defaults to 1. |
1
|
retry_on
|
Optional[Tuple[Type[Exception], ...]]
|
A tuple of errors to retry on. If None, retries on all errors. Defaults to None. |
None
|
ignore
|
Optional[Tuple[Type[Exception], ...]]
|
A tuple of errors to ignore (not retry on). If None, no errors are ignored. Defaults to None. |
None
|
resource_type
|
Optional[str]
|
The type of resource being exhausted. Defaults to None. |
None
|
lang
|
str
|
The language for the error message (default: "fa"). |
FA
|
Returns:
Name | Type | Description |
---|---|---|
Callable |
Callable[[F], F]
|
The decorated function with retry logic. |
Example
To use this decorator, apply it to a function:
@retry_decorator(max_retries=3, delay=1, retry_on=(ValueError,), ignore=(TypeError,), resource_type="API")
def unreliable_function():
if random.random() < 0.5:
raise ValueError("Temporary failure")
return "Success"
result = unreliable_function()
Output:
Source code in archipy/helpers/decorators/retry.py
options: show_root_heading: true show_source: true
Singleton Decorator¶
The singleton decorator ensures that a class has only one instance throughout the application lifecycle.
from archipy.helpers.decorators.singleton import singleton
@singleton
class DatabaseConnection:
def __init__(self):
self.connection = create_connection()
# Both instances will be the same
db1 = DatabaseConnection()
db2 = DatabaseConnection()
assert db1 is db2
archipy.helpers.decorators.singleton.singleton_decorator(*, thread_safe=True)
¶
A decorator to create thread-safe Singleton classes.
This decorator ensures that only one instance of a class is created. It supports an optional
thread_safe
parameter to control whether thread-safety mechanisms (e.g., locks) should be used.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
thread_safe
|
bool
|
If True, enables thread-safety for instance creation. Defaults to True. |
True
|
Returns:
Name | Type | Description |
---|---|---|
function |
Callable[[type[Any]], Callable[..., Any]]
|
A decorator function that can be applied to a class. |
Example
To create a Singleton class, apply the singleton
decorator and optionally specify
whether thread-safety should be enabled:
@singleton(thread_safe=True)
class MySingletonClass:
def __init__(self, value):
self.value = value
# Create instances of MySingletonClass
instance1 = MySingletonClass(10)
instance2 = MySingletonClass(20)
# Verify that both instances are the same
print(instance1.value) # Output: 10
print(instance2.value) # Output: 10
print(instance1 is instance2) # Output: True
Source code in archipy/helpers/decorators/singleton.py
options: show_root_heading: true show_source: true
SQLAlchemy Atomic Decorator¶
The SQLAlchemy atomic decorator provides transaction management for database operations.
from archipy.helpers.decorators.sqlalchemy_atomic import sqlalchemy_atomic
@sqlalchemy_atomic
def create_user(username: str, email: str):
user = User(username=username, email=email)
db.session.add(user)
# If any operation fails, the entire transaction is rolled back
db.session.commit()
SQLAlchemy atomic transaction decorators.
This module provides decorators for managing SQLAlchemy transactions with automatic commit/rollback and support for different database types (PostgreSQL, SQLite, StarRocks).
archipy.helpers.decorators.sqlalchemy_atomic.sqlalchemy_atomic_decorator(db_type, is_async=False, function=None)
¶
Factory for creating SQLAlchemy atomic transaction decorators.
This decorator ensures that a function runs within a database transaction for the specified database type. If the function succeeds, the transaction is committed; otherwise, it is rolled back. Supports both synchronous and asynchronous functions.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
db_type
|
str
|
The database type ("postgres", "sqlite", or "starrocks"). |
required |
is_async
|
bool
|
Whether the function is asynchronous. Defaults to False. |
False
|
function
|
Callable | None
|
The function to wrap. If None, returns a partial function. |
None
|
Returns:
Type | Description |
---|---|
Callable[..., Any] | partial[Callable[..., Any]]
|
Callable | partial: The wrapped function or a partial function for later use. |
Raises:
Type | Description |
---|---|
ValueError
|
If an invalid db_type is provided. |
DatabaseSerializationError
|
If a serialization failure is detected. |
DatabaseDeadlockError
|
If an operational error occurs due to a deadlock. |
DatabaseTransactionError
|
If a transaction-related error occurs. |
DatabaseQueryError
|
If a query-related error occurs. |
DatabaseConnectionError
|
If a connection-related error occurs. |
DatabaseConstraintError
|
If a constraint violation is detected. |
DatabaseIntegrityError
|
If an integrity violation is detected. |
DatabaseTimeoutError
|
If a database operation times out. |
DatabaseConfigurationError
|
If there's an error in the database configuration. |
Example
Synchronous PostgreSQL example¶
@sqlalchemy_atomic_decorator(db_type="postgres") def update_user(id: int, name: str) -> None: # Database operations pass
Asynchronous SQLite example¶
@sqlalchemy_atomic_decorator(db_type="sqlite", is_async=True) async def update_record(id: int, data: str) -> None: # Async database operations pass
Source code in archipy/helpers/decorators/sqlalchemy_atomic.py
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
|
archipy.helpers.decorators.sqlalchemy_atomic.postgres_sqlalchemy_atomic_decorator(function=None)
¶
Decorator for PostgreSQL atomic transactions.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
function
|
Callable | None
|
The function to wrap. If None, returns a partial function. |
None
|
Returns:
Type | Description |
---|---|
Callable[..., Any] | partial
|
Callable | partial: The wrapped function or a partial function for later use. |
Source code in archipy/helpers/decorators/sqlalchemy_atomic.py
archipy.helpers.decorators.sqlalchemy_atomic.async_postgres_sqlalchemy_atomic_decorator(function=None)
¶
Decorator for asynchronous PostgreSQL atomic transactions.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
function
|
Callable | None
|
The function to wrap. If None, returns a partial function. |
None
|
Returns:
Type | Description |
---|---|
Callable[..., Any] | partial
|
Callable | partial: The wrapped function or a partial function for later use. |
Source code in archipy/helpers/decorators/sqlalchemy_atomic.py
archipy.helpers.decorators.sqlalchemy_atomic.sqlite_sqlalchemy_atomic_decorator(function=None)
¶
Decorator for SQLite atomic transactions.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
function
|
Callable | None
|
The function to wrap. If None, returns a partial function. |
None
|
Returns:
Type | Description |
---|---|
Callable[..., Any] | partial
|
Callable | partial: The wrapped function or a partial function for later use. |
Source code in archipy/helpers/decorators/sqlalchemy_atomic.py
archipy.helpers.decorators.sqlalchemy_atomic.async_sqlite_sqlalchemy_atomic_decorator(function=None)
¶
Decorator for asynchronous SQLite atomic transactions.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
function
|
Callable | None
|
The function to wrap. If None, returns a partial function. |
None
|
Returns:
Type | Description |
---|---|
Callable[..., Any] | partial
|
Callable | partial: The wrapped function or a partial function for later use. |
Source code in archipy/helpers/decorators/sqlalchemy_atomic.py
archipy.helpers.decorators.sqlalchemy_atomic.starrocks_sqlalchemy_atomic_decorator(function=None)
¶
Decorator for StarRocks atomic transactions.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
function
|
Callable | None
|
The function to wrap. If None, returns a partial function. |
None
|
Returns:
Type | Description |
---|---|
Callable[..., Any] | partial
|
Callable | partial: The wrapped function or a partial function for later use. |
Source code in archipy/helpers/decorators/sqlalchemy_atomic.py
archipy.helpers.decorators.sqlalchemy_atomic.async_starrocks_sqlalchemy_atomic_decorator(function=None)
¶
Decorator for asynchronous StarRocks atomic transactions.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
function
|
Callable | None
|
The function to wrap. If None, returns a partial function. |
None
|
Returns:
Type | Description |
---|---|
Callable[..., Any] | partial
|
Callable | partial: The wrapped function or a partial function for later use. |
Source code in archipy/helpers/decorators/sqlalchemy_atomic.py
options: show_root_heading: true show_source: true
Interceptors¶
FastAPI Interceptors¶
FastAPI Rest Rate Limit Handler¶
Provides rate limiting functionality for FastAPI endpoints.
from archipy.helpers.interceptors.fastapi.rate_limit import FastAPIRestRateLimitHandler
from fastapi import FastAPI
app = FastAPI()
rate_limit_handler = FastAPIRestRateLimitHandler(
redis_client=redis_client,
rate_limit=100, # requests per minute
rate_limit_period=60
)
@app.get("/api/data")
@rate_limit_handler
async def get_data():
return {"data": "protected by rate limit"}
archipy.helpers.interceptors.fastapi.rate_limit.fastapi_rest_rate_limit_handler.FastAPIRestRateLimitHandler
¶
A rate-limiting handler for FastAPI REST endpoints using Redis for tracking.
This class provides rate-limiting functionality by tracking the number of requests made to a specific endpoint within a defined time window. If the request limit is exceeded, it raises an HTTP 429 Too Many Requests error.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
calls_count
|
StrictInt
|
The maximum number of allowed requests within the time window. |
1
|
milliseconds
|
StrictInt
|
The time window in milliseconds. |
0
|
seconds
|
StrictInt
|
The time window in seconds. |
0
|
minutes
|
StrictInt
|
The time window in minutes. |
0
|
hours
|
StrictInt
|
The time window in hours. |
0
|
days
|
StrictInt
|
The time window in days. |
0
|
query_params
|
set(StrictStr
|
request query parameters for rate-limiting based on query params. |
None
|
Source code in archipy/helpers/interceptors/fastapi/rate_limit/fastapi_rest_rate_limit_handler.py
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
|
archipy.helpers.interceptors.fastapi.rate_limit.fastapi_rest_rate_limit_handler.FastAPIRestRateLimitHandler.__init__(calls_count=1, milliseconds=0, seconds=0, minutes=0, hours=0, days=0, query_params=None)
¶
Initialize the rate limit handler with specified time window and request limits.
The time window is calculated by combining all time unit parameters into milliseconds. At least one time unit parameter should be greater than 0 to create a valid window.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
calls_count
|
StrictInt
|
Maximum number of allowed requests within the time window. Defaults to 1. |
1
|
milliseconds
|
StrictInt
|
Number of milliseconds in the time window. Defaults to 0. |
0
|
seconds
|
StrictInt
|
Number of seconds in the time window. Defaults to 0. |
0
|
minutes
|
StrictInt
|
Number of minutes in the time window. Defaults to 0. |
0
|
hours
|
StrictInt
|
Number of hours in the time window. Defaults to 0. |
0
|
days
|
StrictInt
|
Number of days in the time window. Defaults to 0. |
0
|
query_params
|
set[StrictStr] | None
|
Set of query parameter names to include in rate limit key generation. If None, no query parameters will be used. Defaults to None. |
None
|
Example
Allow 100 requests per minute¶
handler = FastAPIRestRateLimitHandler(calls_count=100, minutes=1)
Allow 1000 requests per day with specific query params¶
handler = FastAPIRestRateLimitHandler( ... calls_count=1000, ... days=1, ... query_params={'user_id', 'action'} ... )
Source code in archipy/helpers/interceptors/fastapi/rate_limit/fastapi_rest_rate_limit_handler.py
archipy.helpers.interceptors.fastapi.rate_limit.fastapi_rest_rate_limit_handler.FastAPIRestRateLimitHandler.__call__(request)
async
¶
Handles the rate-limiting logic for incoming requests.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request
|
Request
|
The incoming FastAPI request. |
required |
Raises:
Type | Description |
---|---|
HTTPException
|
If the rate limit is exceeded, an HTTP 429 Too Many Requests error is raised. |
Source code in archipy/helpers/interceptors/fastapi/rate_limit/fastapi_rest_rate_limit_handler.py
options: show_root_heading: true show_source: true
gRPC Interceptors¶
gRPC interceptors for tracing and monitoring:
archipy.helpers.interceptors.grpc.trace.client_interceptor.GrpcClientTraceInterceptor
¶
Bases: BaseGrpcClientInterceptor
A gRPC client interceptor for tracing requests using Elastic APM and Sentry APM.
This interceptor injects the Elastic APM trace parent header into gRPC client requests to enable distributed tracing across services. It also creates Sentry transactions to monitor the performance of gRPC calls.
Source code in archipy/helpers/interceptors/grpc/trace/client_interceptor.py
archipy.helpers.interceptors.grpc.trace.client_interceptor.GrpcClientTraceInterceptor.intercept(method, request_or_iterator, call_details)
¶
Intercepts a gRPC client call to inject the Elastic APM trace parent header and monitor performance with Sentry.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
method
|
Callable
|
The gRPC method being intercepted. |
required |
request_or_iterator
|
Any
|
The request or request iterator. |
required |
call_details
|
ClientCallDetails
|
Details of the gRPC call. |
required |
Returns:
Name | Type | Description |
---|---|---|
Any |
The result of the intercepted gRPC method. |
Notes
- If Elastic APM is disabled, the interceptor does nothing and passes the call through.
- If no trace parent header is available, the interceptor does nothing and passes the call through.
Source code in archipy/helpers/interceptors/grpc/trace/client_interceptor.py
archipy.helpers.interceptors.grpc.trace.client_interceptor.AsyncGrpcClientTraceInterceptor
¶
Bases: BaseAsyncGrpcClientInterceptor
An asynchronous gRPC client interceptor for tracing requests using Elastic APM.
This interceptor injects the Elastic APM trace parent header into asynchronous gRPC client requests to enable distributed tracing across services.
Source code in archipy/helpers/interceptors/grpc/trace/client_interceptor.py
archipy.helpers.interceptors.grpc.trace.client_interceptor.AsyncGrpcClientTraceInterceptor.intercept(method, request_or_iterator, call_details)
async
¶
Intercepts an asynchronous gRPC client call to inject the Elastic APM trace parent header.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
method
|
Callable
|
The asynchronous gRPC method being intercepted. |
required |
request_or_iterator
|
Any
|
The request or request iterator. |
required |
call_details
|
ClientCallDetails
|
Details of the gRPC call. |
required |
Returns:
Name | Type | Description |
---|---|---|
Any |
The result of the intercepted gRPC method. |
Notes
- If Elastic APM is disabled, the interceptor does nothing and passes the call through.
- If no trace parent header is available, the interceptor does nothing and passes the call through.
Source code in archipy/helpers/interceptors/grpc/trace/client_interceptor.py
options: show_root_heading: true show_source: true
archipy.helpers.interceptors.grpc.trace.server_interceptor.GrpcServerTraceInterceptor
¶
Bases: BaseGrpcServerInterceptor
A gRPC server interceptor for tracing requests using Elastic APM.
This interceptor captures and traces gRPC server requests, enabling distributed tracing across services. It integrates with Elastic APM to monitor and log transactions.
Source code in archipy/helpers/interceptors/grpc/trace/server_interceptor.py
archipy.helpers.interceptors.grpc.trace.server_interceptor.GrpcServerTraceInterceptor.intercept(method, request, context)
¶
Intercepts a gRPC server call to trace the request using Elastic APM.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
method
|
Callable
|
The gRPC method being intercepted. |
required |
request
|
Any
|
The request object passed to the method. |
required |
context
|
ServicerContext
|
The context of the gRPC call. |
required |
Returns:
Name | Type | Description |
---|---|---|
Any |
The result of the intercepted gRPC method. |
Raises:
Type | Description |
---|---|
Exception
|
If an exception occurs during the method execution, it is captured and logged. |
Notes
- If Elastic APM is disabled, the interceptor does nothing and passes the call through.
- If a trace parent header is present in the metadata, it is used to link the transaction to the distributed trace.
- If no trace parent header is present, a new transaction is started.
Source code in archipy/helpers/interceptors/grpc/trace/server_interceptor.py
options: show_root_heading: true show_source: true
Metaclasses¶
Singleton Metaclass¶
A metaclass implementation of the singleton pattern.
from archipy.helpers.metaclasses.singleton import Singleton
class DatabaseConnection(metaclass=Singleton):
def __init__(self):
self.connection = create_connection()
# Both instances will be the same
db1 = DatabaseConnection()
db2 = DatabaseConnection()
assert db1 is db2
archipy.helpers.metaclasses.singleton.Singleton
¶
Bases: type
A thread-safe Singleton metaclass that ensures only one instance of a class is created.
This metaclass can be used to create Singleton classes. It supports an optional thread_safe
parameter to control whether thread-safety mechanisms (e.g., locks) should be used.
Attributes:
Name | Type | Description |
---|---|---|
_instances |
dict
|
A dictionary to store instances of Singleton classes. |
_lock |
Lock
|
A lock to ensure thread-safe instance creation. |
Example
To create a Singleton class, use the Singleton
metaclass and optionally specify
whether thread-safety should be enabled:
class MySingletonClass(metaclass=Singleton, thread_safe=True):
def __init__(self, value):
self.value = value
# Create instances of MySingletonClass
instance1 = MySingletonClass(10)
instance2 = MySingletonClass(20)
# Verify that both instances are the same
print(instance1.value) # Output: 10
print(instance2.value) # Output: 10
print(instance1 is instance2) # Output: True
Source code in archipy/helpers/metaclasses/singleton.py
archipy.helpers.metaclasses.singleton.Singleton.__new__(name, bases, dct, **kwargs)
¶
Create a new Singleton metaclass instance.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name
|
str
|
The name of the class. |
required |
bases
|
tuple
|
The base classes of the class. |
required |
dct
|
dict
|
The namespace containing the class attributes. |
required |
**kwargs
|
object
|
Additional keyword arguments, including |
{}
|
Returns:
Name | Type | Description |
---|---|---|
type |
type
|
A new metaclass instance. |
Source code in archipy/helpers/metaclasses/singleton.py
archipy.helpers.metaclasses.singleton.Singleton.__call__(*args, **kwargs)
¶
Create or return the Singleton instance of the class.
If thread_safe
is True, a lock is used to ensure that only one instance is created
even in a multi-threaded environment. If thread_safe
is False, no locking mechanism
is used, which may result in multiple instances being created in a multi-threaded context.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
*args
|
object
|
Positional arguments to pass to the class constructor. |
()
|
**kwargs
|
object
|
Keyword arguments to pass to the class constructor. |
{}
|
Returns:
Name | Type | Description |
---|---|---|
object |
SingletonInstance
|
The Singleton instance of the class. |
Source code in archipy/helpers/metaclasses/singleton.py
options: show_root_heading: true show_source: true
Key Classes¶
Retry Decorator¶
Function: archipy.helpers.decorators.retry.retry
A decorator that retries a function call when it fails, with configurable:
- Maximum number of attempts
- Delay between attempts
- Backoff strategy
- Exception types to catch
Singleton¶
Class: archipy.helpers.metaclasses.singleton.Singleton
A metaclass that ensures a class has only one instance. Features:
- Thread-safe implementation
- Lazy initialization
- Support for inheritance
- Clear instance access
FastAPIRestRateLimitHandler¶
Class: archipy.helpers.interceptors.fastapi.rate_limit.fastapi_rest_rate_limit_handler.FastAPIRestRateLimitHandler
A rate limiting handler for FastAPI applications that:
- Supports Redis-based rate limiting
- Configurable rate limits and periods
- Customizable response handling
- Support for multiple rate limit rules