๐ ๏ธ Essential gear for Python developers: decorators, validators, file utils, logging โ all in one lightweight, zero-dependency package
Project description
DevGear is a lightweight, zero-dependency Python toolkit that provides essential utilities every developer needs: powerful decorators, data validators, file operations, logging setup, and timing tools โ all in one package.
โจ Why DevGear?
| Feature | Benefit |
|---|---|
| ๐ Zero Dependencies | Pure Python โ just install and use |
| ๐ฆ All-in-One | No need for 10 different packages |
| ๐ฏ Type Hints | Full IDE support & autocompletion |
| โก Lightweight | < 50KB, fast import |
| ๐งช Well Tested | 95%+ code coverage |
| ๐ Well Documented | Examples for everything |
๐ฆ Installation
pip install devgear
๐ Quick Start
๐ Decorators
from devgear import retry, timeout, memoize, timer, deprecated
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Retry with exponential backoff
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@retry(max_attempts=3, delay=1.0, backoff=2.0)
def fetch_from_api():
"""Automatically retries on failure: 1s โ 2s โ 4s"""
response = requests.get("https://api.example.com")
response.raise_for_status()
return response.json()
# With specific exceptions and callback
@retry(
max_attempts=5,
exceptions=(ConnectionError, TimeoutError),
on_retry=lambda e, attempt: print(f"Retry {attempt}: {e}")
)
def connect_to_database():
return Database.connect()
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Timeout - prevent hanging operations
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@timeout(seconds=30)
def process_large_file(path):
"""Raises TimeoutExpiredError if takes > 30 seconds"""
with open(path) as f:
return analyze(f.read())
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Memoize - cache expensive computations
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@memoize(maxsize=100, ttl=300) # 100 items, 5 min TTL
def expensive_calculation(x, y):
"""Result cached for 5 minutes"""
time.sleep(2) # Simulate heavy computation
return x ** y
# Cache info and management
expensive_calculation.cache_info() # {'size': 10, 'maxsize': 100, 'ttl': 300}
expensive_calculation.cache_clear() # Clear all cached values
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Timer - measure execution time
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@timer()
def train_model():
# ... training code ...
pass
# Output: Function 'train_model' took 42.1234 seconds
# With custom logger
@timer(logger=logging.info, precision=2)
def quick_task():
pass
# Logs: Function 'quick_task' took 0.01 seconds
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Deprecated - mark old functions
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@deprecated(
reason="Use 'new_api_call' for better performance",
version="2.0.0",
replacement="new_api_call"
)
def old_api_call():
pass
# Warning: Function 'old_api_call' is deprecated (since version 2.0.0):
# Use 'new_api_call' for better performance. Use 'new_api_call' instead
โ Validators
from devgear import (
validate_email, validate_url, validate_phone,
validate_json, validate_uuid, validate_ip,
validate_credit_card, is_empty, is_numeric
)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Email validation
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
validate_email("user@example.com") # โ
True
validate_email("user.name+tag@domain.co.uk") # โ
True
validate_email("invalid-email") # โ False
validate_email("missing@domain") # โ False
# Strict mode (additional RFC checks)
validate_email("valid@example.com", strict=True)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# URL validation
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
validate_url("https://github.com/user/repo") # โ
True
validate_url("http://localhost:8080/api") # โ
True
validate_url("ftp://files.example.com") # โ False (not http/https)
# Require HTTPS
validate_url("http://example.com", require_https=True) # โ False
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Phone validation
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
validate_phone("+1-234-567-8900") # โ
True
validate_phone("+7 (999) 123-45-67") # โ
True
validate_phone("123") # โ False (too short)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# JSON validation
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
validate_json('{"name": "John", "age": 30}') # โ
True
validate_json('[1, 2, 3]') # โ
True
validate_json('{"invalid": }') # โ False
# Get parsed data
is_valid, data = validate_json('{"key": "value"}', return_parsed=True)
if is_valid:
print(data["key"]) # "value"
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# UUID validation
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
validate_uuid("550e8400-e29b-41d4-a716-446655440000") # โ
True
validate_uuid("550e8400-e29b-41d4-a716-446655440000", version=4) # โ
True
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# IP address validation
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
validate_ip("192.168.1.1") # โ
True (IPv4)
validate_ip("::1") # โ
True (IPv6)
validate_ip("192.168.1.1", version=4) # โ
True
validate_ip("::1", version=6) # โ
True
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Credit card validation (Luhn algorithm)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
validate_credit_card("4532015112830366") # โ
True
validate_credit_card("4532-0151-1283-0366") # โ
True (with dashes)
validate_credit_card("1234567890123456") # โ False
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Utility validators
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Check for empty values
is_empty(None) # โ
True
is_empty("") # โ
True
is_empty(" ") # โ
True (whitespace only)
is_empty([]) # โ
True
is_empty({}) # โ
True
is_empty(0) # โ False (0 is a value!)
is_empty("hello") # โ False
# Check for numeric values
is_numeric(123) # โ
True
is_numeric(12.34) # โ
True
is_numeric("123") # โ
True
is_numeric("-45.67") # โ
True
is_numeric("abc") # โ False
is_numeric("-5", allow_negative=False) # โ False
is_numeric("3.14", allow_float=False) # โ False
๐ File Operations
from devgear import (
read_file, write_file,
read_json, write_json,
read_yaml, write_yaml,
atomic_write, safe_delete,
ensure_dir, get_file_hash,
list_files
)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Text files
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Simple read/write
content = read_file("data.txt")
write_file("output.txt", "Hello, World!")
# With encoding
content = read_file("russian.txt", encoding="cp1251")
# With default value (no exception if missing)
config = read_file("optional.txt", default="")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# JSON files
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Read with default
config = read_json("config.json", default={"debug": False})
# Write with formatting
write_json("output.json", {
"name": "DevGear",
"version": "1.0.0",
"features": ["decorators", "validators", "file-ops"]
}, indent=4)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# YAML files (requires: pip install devgear[yaml])
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
config = read_yaml("config.yaml", default={})
write_yaml("output.yaml", {"database": {"host": "localhost"}})
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Atomic writes (safe for concurrent access)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with atomic_write("critical_data.json") as f:
json.dump(important_data, f)
# File is either fully written or not modified at all
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Directory operations
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Create directory tree
ensure_dir("path/to/nested/directory")
# Safe delete (no error if missing)
safe_delete("temp_file.txt")
safe_delete("temp_directory/", missing_ok=True)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# File hashing
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
sha256 = get_file_hash("document.pdf")
md5 = get_file_hash("document.pdf", algorithm="md5")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# List files
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# All Python files in directory
py_files = list_files("src", "*.py")
# Recursive search
all_py = list_files("project", "*.py", recursive=True)
๐ Logging
from devgear import setup_logger, get_logger, LogLevel
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Quick setup with colors
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
logger = setup_logger("myapp")
logger.debug("Debug message") # Cyan
logger.info("Info message") # Green
logger.warning("Warning message") # Yellow
logger.error("Error message") # Red
logger.critical("Critical!") # Magenta
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# With file output and rotation
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
logger = setup_logger(
name="myapp",
level=LogLevel.DEBUG,
file_path="logs/app.log",
file_max_bytes=10_000_000, # 10 MB per file
file_backup_count=5, # Keep 5 backup files
colored=True # Colors in console
)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Custom format
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
logger = setup_logger(
"api",
format_string="%(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(message)s",
date_format="%Y-%m-%d %H:%M:%S"
)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Get existing logger
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# In another module
logger = get_logger("myapp")
logger.info("Using the same logger")
โฑ๏ธ Timing & Rate Limiting
from devgear import Timer, timeit, rate_limiter, RateLimiter
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Timer context manager
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with Timer("Database query"):
result = db.execute(complex_query)
# Output: Database query: 0.2345s
# Get elapsed time programmatically
with Timer(auto_print=False) as t:
process_data()
print(f"Processing took {t.elapsed:.2f}s ({t.elapsed_ms:.0f}ms)")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Timer as decorator
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@timeit
def my_function():
time.sleep(1)
# Output: my_function: 1.0012s
@timeit(name="Custom Name", logger=logging.debug)
def another_function():
pass
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Rate limiting - decorator
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@rate_limiter(rate=10, per=1.0) # Max 10 calls per second
def api_call():
return requests.get("https://api.example.com")
# Will automatically slow down to respect rate limit
for i in range(100):
api_call()
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Rate limiting - context manager
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
limiter = RateLimiter(rate=5, per=1.0) # 5 ops per second
for item in items:
with limiter:
process(item)
# Or manually
for item in items:
wait_time = limiter.acquire()
if wait_time > 0:
print(f"Rate limited, waited {wait_time:.2f}s")
process(item)
๐ง More Decorators
from devgear import singleton, throttle, debug, catch_exceptions, run_async
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Singleton pattern
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@singleton
class DatabaseConnection:
def __init__(self, host="localhost"):
self.host = host
self.connect()
db1 = DatabaseConnection()
db2 = DatabaseConnection()
assert db1 is db2 # Same instance!
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Throttle - limit call frequency
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@throttle(calls=5, period=60.0) # Max 5 calls per minute
def send_notification(user, message):
email.send(user, message)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Debug - print call info
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@debug(show_args=True, show_result=True, show_time=True)
def calculate(x, y, operation="add"):
return x + y if operation == "add" else x - y
calculate(10, 5, operation="add")
# [DEBUG] Calling calculate(10, 5, operation='add')
# [DEBUG] calculate returned: 15
# [DEBUG] calculate took 0.000012s
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Catch exceptions gracefully
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@catch_exceptions(ValueError, ZeroDivisionError, default=0)
def safe_divide(a, b):
return a / b
safe_divide(10, 0) # Returns 0 instead of raising
# With custom handler
@catch_exceptions(
Exception,
handler=lambda e: {"error": str(e), "status": "failed"}
)
def risky_operation():
raise RuntimeError("Something went wrong")
result = risky_operation() # {"error": "Something went wrong", "status": "failed"}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Run sync function asynchronously
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@run_async()
def blocking_io_operation():
time.sleep(5)
return "done"
future = blocking_io_operation() # Returns immediately
# ... do other work ...
result = future.result() # Wait for completion
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 devgear-1.0.0.tar.gz.
File metadata
- Download URL: devgear-1.0.0.tar.gz
- Upload date:
- Size: 16.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a586fd71f8a5afed2eb645be82ff7818fbcc43d0d1738fc06698b033a0a44161
|
|
| MD5 |
7665782ea18ffed5f86c80ee189d6e9b
|
|
| BLAKE2b-256 |
ece8dd44e29ebd3a4034c773c628576547d173a623acf1832ad69654ae4032d4
|
File details
Details for the file devgear-1.0.0-py3-none-any.whl.
File metadata
- Download URL: devgear-1.0.0-py3-none-any.whl
- Upload date:
- Size: 7.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5689577d651a5b37c65f41a760ab2e8a79c8cada7ce604650783a212da90d82a
|
|
| MD5 |
24b4fc545009ab8f765d4bbc2b121e01
|
|
| BLAKE2b-256 |
f70e6ff751a941e05db3324c066e178554f7ac7679ea9db3d015946e8e96ea3c
|