Skip to main content

Production-grade currency conversion with smart error handling, encrypted caching, and fuzzy locale matching

Project description

pypenny: Robust Currency Conversion Solution

Python 3.8+ License: MIT Code style: black

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

๐Ÿ“ž Support


Made with โค๏ธ for developers who need reliable currency handling

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pypenny-0.1.0.post1.tar.gz (37.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pypenny-0.1.0.post1-py3-none-any.whl (29.4 kB view details)

Uploaded Python 3

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

Hashes for pypenny-0.1.0.post1.tar.gz
Algorithm Hash digest
SHA256 924488b97871ddff9ebae5d70e082c56d683d8ccdffdd1022754af845da51133
MD5 43440633673a1509eff1d1258711439d
BLAKE2b-256 d9d363569835a4518ca50c1eefa1b0080e49212498112632104704a7d8991795

See more details on using hashes here.

File details

Details for the file pypenny-0.1.0.post1-py3-none-any.whl.

File metadata

File hashes

Hashes for pypenny-0.1.0.post1-py3-none-any.whl
Algorithm Hash digest
SHA256 c82facfedfefabc217aa1feb3158a27b0aea61e4811cf6043fa3e148c93fde3c
MD5 0a2e15f77a1af93c5a09d439dfe07c4a
BLAKE2b-256 3159952599de0964e9a1131755ccdce397a7199edbc4eece0daf6e91c9e77f6d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page