Production-grade currency conversion with smart error handling, encrypted caching, and fuzzy locale matching
Project description
pypenny: Robust Currency Conversion Solution
Production-grade currency conversion library with smart error handling, encrypted caching, and fuzzy locale matching.
โจ Features
- ๐ฏ Unified API: Simple, intuitive top-level functions for all operations
- ๐ฐ Smart Money Class: Immutable, hashable, and supports arithmetic operations
- ๐ง Smart Error Handling: Fuzzy locale matching auto-corrects typos (
em_USโen_US) - โ๏ธ Flexible Configuration: Control cache behavior and restrict allowed currencies
- ๐ Encrypted Cache: Fernet (AES-128) encryption with cross-platform storage
- ๐ Deduplication Logic: Only 1 record per day if exchange rate unchanged
- ๐ 180+ Currencies: Supports all ISO 4217 currencies via py-moneyed
- ๐ Dual Exchange Strategies: Live network-based + encrypted local cache fallback
- ๐ฆ Zero Config: Works out of the box with sensible defaults
๐ Quick Start
Installation
# Using uv (recommended)
uv pip install pypenny
# Using pip
pip install pypenny
Basic Usage
import pypenny as pp
# Configure (optional, uses defaults if skipped)
pp.config(application_name="MyApp")
# Create money
money_usd = pp.Money('100', 'USD')
# Convert
money_egp = pp.convert(money_usd, 'EGP')
# Format (safe to print!)
print(pp.format(money_egp, locale='ar_EG'))
# Output: โ4,752.00 ุฌ.ู
.โ
Strict Configuration (Production)
import pypenny as pp
pp.config(
application_name="ProductionApp",
allow_cache_fallback=False, # Fail fast on network errors
allowed_currencies=['USD', 'EGP'], # Whitelist only
cache_max_records=10,
cache_retention_days=7
)
# This works
money_usd = pp.Money('100', 'USD')
# This raises CurrencyNotAllowedError with helpful message
try:
money_eur = pp.Money('100', 'EUR')
except pp.CurrencyNotAllowedError as e:
print(e)
# Error: Currency 'EUR' not allowed. Allowed: USD, EGP.
# Update config.allowed_currencies to include 'EUR'.
๐ Key Features
1. Arithmetic Operations
The Money class supports intuitive arithmetic operations:
m1 = pp.Money('100', 'USD')
m2 = pp.Money('50', 'USD')
# Arithmetic
total = m1 + m2 # 150.00 USD
diff = m1 - m2 # 50.00 USD
doubled = m1 * 2 # 200.00 USD
halved = m1 / 2 # 50.00 USD
# Comparison
is_greater = m1 > m2 # True
2. Fuzzy Locale Matching
Automatically corrects common locale mistakes:
pp.format(money, locale='EN_us') # โ Normalized to 'en_US'
pp.format(money, locale='US_EN') # โ Swapped to 'en_US'
pp.format(money, locale='em_US') # โ Typo corrected to 'en_US'
pp.format(money, locale='US') # โ Alias resolved to 'en_US'
3. Encrypted Cache with Deduplication
# Cache automatically stores exchange rates
money_converted = pp.convert(money_usd, 'EGP')
# Get cache statistics
stats = pp.get_cache_stats()
print(stats['total_records']) # Number of cached rates
print(stats['cache_file']) # Path to encrypted cache file
# Cleanup old records
pp.cleanup_cache()
4. Exchange Strategies
# LIVE: Always fetch from network
converted = pp.convert(money, 'EGP', strategy='live')
# CACHED: Use local cache only
converted = pp.convert(money, 'EGP', strategy='cached')
# AUTO: Try live, fallback to cache (default)
converted = pp.convert(money, 'EGP', strategy='auto')
๐ง Configuration Options
pp.config(
# Required
application_name: str, # For cache directory naming
# Cache behavior
allow_cache_fallback: bool = True, # Fallback to cache on network failure
cache_max_records: int = 7, # Max records per currency pair
cache_retention_days: int = 3, # Days to retain cached records
cache_file_path: str = None, # Custom cache path (None = platformdirs)
# Currency restrictions
allowed_currencies: List[str] = None, # Whitelist (None = all allowed)
# Exchange settings
default_exchange_strategy: str = 'auto', # 'live', 'cached', 'auto'
default_locale: str = 'en_US',
# API settings
api_key: str = None,
api_timeout: int = 5,
api_max_retries: int = 3,
)
๐งช Testing
# Install dev dependencies
uv pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=. --cov-report=html
# Run stress tests
pytest tests/test_stress.py -v
๐๏ธ Architecture
โโโโโโโโโโโโโโโ
โ pypenny โ โ Unified Package API
โโโโโโโโฌโโโโโโโ
โ
โโโโโโโโผโโโโโโโโโ
โCurrencyManagerโ
โโโโโโโโฌโโโโโโโโโ
โ
โโโโโโดโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโโ
โผ โผ โผ โผ
โโโโโโโโโโ โโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโโ
โ Config โ โLocaleโ โExchange โ โEncryptionโ
โ โ โMatch โ โ Cache โ โ Utils โ
236: โโโโโโโโโโ โโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโโ
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Built on py-moneyed for robust currency handling
- Uses Babel for locale-aware formatting
- Encryption via cryptography
- Cross-platform paths via platformdirs
๐ Support
- ๐ Documentation
- ๐ Issue Tracker
- ๐ฌ Discussions
Made with โค๏ธ for developers who need reliable currency handling
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 pypenny-0.1.0.post1.tar.gz.
File metadata
- Download URL: pypenny-0.1.0.post1.tar.gz
- Upload date:
- Size: 37.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
924488b97871ddff9ebae5d70e082c56d683d8ccdffdd1022754af845da51133
|
|
| MD5 |
43440633673a1509eff1d1258711439d
|
|
| BLAKE2b-256 |
d9d363569835a4518ca50c1eefa1b0080e49212498112632104704a7d8991795
|
File details
Details for the file pypenny-0.1.0.post1-py3-none-any.whl.
File metadata
- Download URL: pypenny-0.1.0.post1-py3-none-any.whl
- Upload date:
- Size: 29.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c82facfedfefabc217aa1feb3158a27b0aea61e4811cf6043fa3e148c93fde3c
|
|
| MD5 |
0a2e15f77a1af93c5a09d439dfe07c4a
|
|
| BLAKE2b-256 |
3159952599de0964e9a1131755ccdce397a7199edbc4eece0daf6e91c9e77f6d
|