A comprehensive utility library that eliminates boilerplate from everyday Python code.
The Problem
Every project has the same utilities scattered around: that function to slugify strings, the one that safely gets nested dict values, the email validator you copied from Stack Overflow. You end up with a utils.py file that grows organically and becomes unmaintainable.
This library is my answer: a well-organized, thoroughly tested collection of utilities I actually use, packaged for reuse.
Design Principles
Static Methods Only - No classes to instantiate. Just import and call:
from utils import String
String.slugify(text='Hello World!') # 'hello-world'
Keyword-Only Arguments - Every method uses keyword-only args for clarity. No guessing what positional arguments mean:
# Clear what each argument does
Dict.deep_get(obj=config, path='database.host', default='localhost')
Zero Core Dependencies - The base utilities have no external dependencies. Optional features (HTTP, Pydantic integration) require their respective packages.
Utility Categories
String Utilities (22 methods)
- Case Conversion: snake_case, camelCase, PascalCase, kebab-case
- Slugify: URL-safe string conversion
- Truncate: Smart truncation with ellipsis
- Hashing: MD5, SHA256, SHA512
- Extraction: Extract emails, URLs, numbers from text
- Padding: Left, right, center padding
Integer Utilities (15 methods)
- Properties: is_even, is_odd, is_prime, is_perfect_square
- Math: factorial, GCD, LCM, power_of_two
- Conversion: to_roman, from_roman, to_words
- Formatting: bytes_to_human (1048576 -> '1 MB')
Dict Utilities (18 methods)
- Deep Access: deep_get, deep_set with dot notation
- Merge: deep_merge for nested dicts
- Transform: map_keys, map_values, filter
- Case Convert: snake_case_keys, camel_case_keys (recursive)
- Flatten/Unflatten: Nested dict <-> flat with dot keys
Iterable Utilities (22 methods)
- Chunking: Split lists into fixed-size batches
- Grouping: Group by key function
- Aggregation: sum_by, avg_by, count_by
- Finding: first, last, find_all with predicates
- Filtering: unique, compact (remove None/empty)
Datetime Utilities (28 methods)
- Parsing: ISO, RFC3339, custom formats
- Arithmetic: add_days, add_months, add_years
- Boundaries: start_of_day, end_of_month, start_of_week
- Human: 'human_time' for relative dates ('3 days ago')
- Comparison: is_weekend, is_business_day, days_between
Validator Utilities (14 methods)
- Format: is_email, is_url, is_uuid, is_phone
- Financial: is_credit_card (Luhn algorithm)
- Geographic: is_latitude, is_longitude, is_timezone
- Content: is_empty, is_numeric, is_hex_color
Path Utilities (12 methods)
- Read/Write: text, lines, JSON with encoding handling
- Operations: copy, move, delete with safety checks
- Info: size, modified_time, extension, exists
Logger Utilities
Structured JSON logging with context:
from utils import Logger
log = Logger.create(name='myapp')
with log.context(user_id='123', request_id='abc'):
log.info(message='Processing request')
# Output: {"timestamp": "...", "level": "INFO",
# "message": "Processing request", "user_id": "123"}
Testing
1,114 tests covering all utilities, edge cases, and error conditions. Tests run in under 5 seconds.
Installation
pip install bp-utils # Core utilities
pip install bp-utils[http] # Adds Session utilities
pip install bp-utils[pydantic] # Adds Pydantic validators
pip install bp-utils[all] # Everything
A pure Python utility library demonstrating library design patterns, comprehensive testing, and optional dependency management.
Architecture
Module Structure:
utils/
__init__.py # Public exports
string.py # StringUtil class
integer.py # IntegerUtil class
dict.py # DictUtil class
iterable.py # IterableUtil class
datetime.py # DatetimeUtil class
validator.py # ValidatorUtil class
path.py # PathUtil class
random.py # RandomUtil class
convert.py # ConvertUtil class
decorator.py # DecoratorUtil class
regex.py # RegexUtil class
encode.py # EncodeUtil class
hash.py # HashUtil class
json_utils.py # JsonUtil class
logger.py # LoggerUtil (requires: none)
session.py # SessionUtil (requires: requests)
pydantic_validator.py # PydanticValidatorUtil (requires: pydantic)
pydantic_field.py # PydanticFieldUtil (requires: pydantic)
json_db.py # JsonDbUtil (requires: pydantic)
beacon.py # BeaconUtil (global state)
Design Patterns
Static Method Pattern - All utilities are static methods on classes:
class StringUtil:
@staticmethod
def slugify(*, text: str, separator: str = '-') -> str:
"""Convert text to URL-safe slug."""
# Implementation
Keyword-Only Enforcement - Bare * in signature forces keyword usage:
def deep_get(*, obj: dict, path: str, default: Any = None) -> Any:
# Caller must use: deep_get(obj=d, path='a.b', default=None)
# Not: deep_get(d, 'a.b', None) # TypeError!
Optional Dependencies - Imports guarded with try/except:
# session.py
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
class SessionUtil:
@staticmethod
def create(**kwargs):
if not HAS_REQUESTS:
raise ImportError('Install requests: pip install bp-utils[http]')
# ...
Selected Implementations
Deep Get with Dot Notation:
@staticmethod
def deep_get(*, obj: dict, path: str, default: Any = None) -> Any:
keys = path.split('.')
result = obj
for key in keys:
if isinstance(result, dict):
result = result.get(key, default)
elif isinstance(result, list) and key.isdigit():
idx = int(key)
result = result[idx] if 0 <= idx < len(result) else default
else:
return default
return result
Luhn Algorithm for Credit Cards:
@staticmethod
def is_credit_card(*, value: str) -> bool:
digits = [int(d) for d in value if d.isdigit()]
if len(digits) < 13:
return False
# Luhn algorithm
checksum = 0
for i, digit in enumerate(reversed(digits)):
if i % 2 == 1:
digit *= 2
if digit > 9:
digit -= 9
checksum += digit
return checksum % 10 == 0
Logger with Thread-Local Context:
import threading
from contextlib import contextmanager
class LoggerUtil:
_context = threading.local()
@classmethod
@contextmanager
def context(cls, **kwargs):
old = getattr(cls._context, 'data', {})
cls._context.data = {**old, **kwargs}
try:
yield
finally:
cls._context.data = old
Testing Strategy
1,114 Tests organized by utility class:
tests/
test_string.py # 85 tests
test_integer.py # 62 tests
test_dict.py # 74 tests
test_iterable.py # 91 tests
test_datetime.py # 112 tests
test_validator.py # 58 tests
...
Coverage Focus:
- Happy path for all methods
- Edge cases (empty input, None, boundary values)
- Error conditions (invalid input types, missing keys)
- Unicode handling
- Thread safety where relevant
Build & Distribution
Hatchling for packaging:
# pyproject.toml
[project.optional-dependencies]
http = ["requests>=2.28.0"]
pydantic = ["pydantic>=2.0.0"]
datetime = ["arrow>=1.3.0"]
all = ["bp-utils[http,pydantic,datetime]"]
Version Management - Follows semantic versioning. Breaking changes bump major version.