Skip to main content

RedenPy

License: MIT

A simple, robust Python utility for currency redenomination.

RedenPy is designed to parse various money formats—including strings with currency symbols and different decimal/thousand separators—and apply a redenomination by a specified number of digits (e.g., converting 1,000,000 to 1,000).


✨ Features

  • Handles Multiple Input Types: Accepts int, float, Decimal, and str inputs.
  • Robust String Parsing: Automatically cleans currency symbols ($, Rp, €, etc.) and non-numeric characters.
  • International Format Support: Intelligently parses both US-style (1,000.00) and EU-style (1.000,00) number formats.
  • Flexible Output: Returns the redenominated value as a str, int, float, or Decimal.
  • Accurate Calculations: Uses the Decimal type internally for all calculations to avoid floating-point errors.

📦 Installation

Install RedenPy directly from PyPI:

pip install redenpy

🚀 Quick Start

from redenpy.core import RedenPy

# 1. Initialize the redenominator
# We want to remove 3 digits (e.g., 1,000 -> 1)
rd = RedenPy(digit=3, rule=None) # 'rule' is reserved for future rounding logic

# 2. Perform redenomination on various inputs

# --- Example 1: Handling International String Formats ---
val_str_us = "$ 1,575,505.75" # Dot as decimal
val_str_eu = "€ 1.575.505,75" # Comma as decimal

# Returns a 'Decimal' object
new_val_us = rd.redenomination(val_str_us, output_type=Decimal)
new_val_eu = rd.redenomination(val_str_eu, output_type=Decimal)

print(f"'{val_str_us}' -> {new_val_us}")
# Output: '$ 1,575,505.75' -> 1575.51

print(f"'{val_str_eu}' -> {new_val_eu}")
# Output: '€ 1.575.505,75' -> 1575.51

# --- Example 2: Controlling Output Type ---
old_val = 1575800

# Get a formatted string with fractions
val_str = rd.redenomination(old_val, fractional=True, output_type=str)
print(f"{old_val} -> '{val_str}' (as string)")
# Output: 1575800 -> '1575,80' (as string)

# Get an integer (truncates the decimal)
val_int = rd.redenomination(old_val, output_type=int)
print(f"{old_val} -> {val_int} (as integer)")
# Output: 1575800 -> 1575 (as integer)

# Get a float
val_float = rd.redenomination(old_val, output_type=float)
print(f"{old_val} -> {val_float} (as float)")
# Output: 1575800 -> 1575.8 (as float)

📖 API Reference

RedenPy(digit, rule)

Initializes the redenomination class.

  • digit (int): The number of digits to remove (e.g., 3 for 1,000 -> 1). This is equivalent to dividing by $10^{digit}$.
  • rule (any): A parameter intended for future, more complex rounding rules (e.g., specific central bank regulations). Note: This parameter is not currently used in the logic. All calculations default to ROUND_HALF_UP to 2 decimal places.
redenomination(money, fractional=False, output_type=str)

Performs the redenomination on a given money value.

  • money (str | int | float | Decimal): The amount to convert.

  • fractional (bool): This parameter only affects the output_type=str.

    • True: Returns the value with a fractional part, separated by a comma (e.g., "1575,51").
    • False: Returns only the whole number part (e.g., "1575").
  • output_type (type): The desired return type for the converted value.

    • str: Returns a formatted string. Behavior is controlled by fractional.
    • Decimal: Returns the redenominated value as a Decimal object, rounded to 2 decimal places.
    • float: Returns the redenominated value as a float.
    • int: Returns the redenominated value as an int (note: this truncates any decimal part after rounding, e.g., 1575.51 becomes 1575).
redenomination_with_rules(money, output_type=str)

accepts a comprehensive rule dictionary that allows full customization of the redenomination process. Below are all possible rules that can be configured.

Complete Rule Reference

1. digit_removal (Integer)

Overrides the default digit removal specified in the constructor.

Property Type Description Example
digit_removal int Number of digits to remove from the right 3 removes 3 zeros (1,000,000 → 1,000)

Example:

rule = {"digit_removal": 6}
# 1,000,000 → 1 (removes 6 digits)

2. rounding (Object)

Controls how numbers are rounded during redenomination.

Property Type Options Default Description
method string "half_up", "half_down", "up", "down", "half_even", "ceiling", "floor", "truncate" "half_up" Rounding method to apply
precision int 0, 1, 2, 3, etc. 2 Number of decimal places to keep

Rounding Methods Explained:

  • "half_up": Round 0.5 up (1.5 → 2, -1.5 → -2)
  • "half_down": Round 0.5 down (1.5 → 1, -1.5 → -1)
  • "up": Always round away from zero (1.1 → 2, -1.1 → -2)
  • "down": Always round toward zero (1.9 → 1, -1.9 → -1)
  • "half_even": Banker's rounding - round to nearest even (1.5 → 2, 2.5 → 2)
  • "ceiling": Always round up (1.1 → 2, -1.1 → -1)
  • "floor": Always round down (1.9 → 1, -1.9 → -2)
  • "truncate": Remove decimal part (1.9 → 1, -1.9 → -1)

Example:

rule = {
    "rounding": {
        "method": "down",
        "precision": 0
    }
}
# 1,234.56 → 1,234 (no decimals, always round down)

3. fractional_policy (Object)

Controls when and how fractional/decimal parts are displayed.

Property Type Options Default Description
always_show bool true, false false Always display decimals even if .00
threshold float or null Any decimal value null Only show decimals if fractional part ≥ threshold
context string "always", "never", "auto" "auto" When to show decimal part

Context Options:

  • "always": Always show decimals (1 → 1.00)
  • "never": Never show decimals (1.75 → 1)
  • "auto": Show decimals only if non-zero (1.00 → 1, 1.50 → 1.50)

Example:

rule = {
    "fractional_policy": {
        "always_show": false,
        "threshold": 0.50,
        "context": "auto"
    }
}
# 1.20 → 1 (below threshold)
# 1.60 → 1.60 (above threshold)

4. rounding_interval (Object)

Round to specific intervals (useful for cash transactions where smallest denomination is 5 or 10 cents).

Property Type Options Default Description
enabled bool true, false false Enable interval rounding
interval int 5, 10, 25, 50, 100, etc. 1 Round to nearest interval
apply_to string "whole", "fractional", "both" "whole" What part to apply rounding to

Apply To Options:

  • "whole": Round the whole number part (123.45 with interval 10 → 120.45)
  • "fractional": Round the fractional part (123.47 with interval 5 → 123.45)
  • "both": Round the entire number (123.47 with interval 5 → 125)

Example:

rule = {
    "rounding_interval": {
        "enabled": True,
        "interval": 5,
        "apply_to": "fractional"
    }
}
# 1.23 → 1.25 (rounded to nearest 0.05)
# 1.27 → 1.25

5. minimum_value (Object)

Handle very small values that should be eliminated or rounded to minimum denomination.

Property Type Options Default Description
enabled bool true, false false Enable minimum value handling
threshold float Any decimal value 0.01 Minimum acceptable value
action string "round_to_zero", "round_to_minimum" "round_to_zero" What to do with sub-threshold values

Action Options:

  • "round_to_zero": Values below threshold become 0
  • "round_to_minimum": Values below threshold become the threshold value

Example:

rule = {
    "minimum_value": {
        "enabled": True,
        "threshold": 0.10,
        "action": "round_to_zero"
    }
}
# 0.05 → 0 (below minimum)
# 0.15 → 0.15 (above minimum)

6. formatting (Object)

Controls the string output format (thousand separators, decimal separators).

Property Type Options Default Description
decimal_separator string ",", "." "," Character to separate decimals
thousand_separator string ".", ",", " ", "" "." Character to separate thousands
force_decimals bool true, false false Always show decimal separator

Example:

rule = {
    "formatting": {
        "decimal_separator": ".",
        "thousand_separator": ",",
        "force_decimals": True
    }
}
# 1234567.5 → 1,234,567.50 (US format)

rule = {
    "formatting": {
        "decimal_separator": ",",
        "thousand_separator": ".",
        "force_decimals": True
    }
}
# 1234567.5 → 1.234.567,50 (European format)

Complete Rule Example

rule = {
    "digit_removal": 3,
    "rounding": {
        "method": "half_up",
        "precision": 2
    },
    "fractional_policy": {
        "always_show": False,
        "threshold": None,
        "context": "auto"
    },
    "rounding_interval": {
        "enabled": False,
        "interval": 5,
        "apply_to": "fractional"
    },
    "minimum_value": {
        "enabled": False,
        "threshold": 0.01,
        "action": "round_to_zero"
    },
    "formatting": {
        "decimal_separator": ",",
        "thousand_separator": ".",
        "force_decimals": False
    }
}

r = RedenPy(digit=3, rule=rule)
result = r.redenomination_with_rules("$ 1,234,567.89")
print(result)  # 1.234,57

Real-World Country Examples

🇮🇩 Indonesia 1965 (Removed 3 zeros)

rule = {
    "digit_removal": 3,
    "rounding": {"method": "half_up", "precision": 2},
    "fractional_policy": {"context": "auto"},
    "formatting": {
        "decimal_separator": ",",
        "thousand_separator": "."
    }
}

🇹🇷 Turkey 2005 (Removed 6 zeros, cash rounding)

rule = {
    "digit_removal": 6,
    "rounding": {"method": "half_up", "precision": 2},
    "rounding_interval": {
        "enabled": True,
        "interval": 5,
        "apply_to": "fractional"
    },
    "fractional_policy": {"context": "always"}
}

🇧🇷 Brazil 1994 (No decimals, eliminate small values)

rule = {
    "digit_removal": 3,
    "rounding": {"method": "down", "precision": 0},
    "fractional_policy": {"context": "never"},
    "minimum_value": {
        "enabled": True,
        "threshold": 1,
        "action": "round_to_zero"
    }
}

🇿🇼 Zimbabwe 2009 (Removed 12 zeros)

rule = {
    "digit_removal": 12,
    "rounding": {"method": "half_up", "precision": 2},
    "fractional_policy": {"context": "auto"}
}

🤝 Contributing

Contributions are welcome! Please feel free to open an issue or submit a pull request.

⚖️ License

This project is licensed under the MIT License - see the LICENSE file for details.

Metadata

Release files for RedenPy 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for RedenPy 0.1.0
File Size Uploaded
redenpy-0.1.0.tar.gz 9.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for RedenPy 0.1.0
File Interpreter ABI Platform
redenpy-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 18.1 kB

Release files / redenpy-0.1.0.tar.gz

Download URL redenpy-0.1.0.tar.gz
Size 9.0 kB
Tags Source
SHA-256 checksum
How to use checksums
2d6e526fd889ccd495360e38847a6a5e0576970a68b3cd404e184a8af418217f
BLAKE2b-256 checksum
How to use checksums
4c2ed6a28711abc096d98cc918b817d5ee6e46eae558dab20b889a5aff81991b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / redenpy-0.1.0-py3-none-any.whl

Download URL redenpy-0.1.0-py3-none-any.whl
Size 9.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
82f2457bafc357d07258b643616cbe5177796648cfb83ae28edcaafcfc7756cd
BLAKE2b-256 checksum
How to use checksums
3946f4988516f000f28890bae0da8fd076d0dc25b5a52d712b3e70c1599b609e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page