Skip to content

Commit fc4db81

Browse files
refactor: improve functions format_currency, convert_real_to_text and tests (#577)
* refactor: improve functions format_currency, convert_real_to_text and tests * fix: typo
1 parent e30fd32 commit fc4db81

2 files changed

Lines changed: 22 additions & 45 deletions

File tree

brutils/currency.py

Lines changed: 22 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,70 @@
11
from decimal import ROUND_DOWN, Decimal, InvalidOperation
2-
from typing import Union
32

43
from num2words import num2words
54

65

7-
def format_currency(value): # type: (float) -> str | None
6+
def format_currency(value: float | int | str | Decimal) -> str | None:
87
"""
9-
Formats a given float as Brazilian currency (R$).
10-
11-
This function takes a float value and returns a formatted string representing
12-
the value as Brazilian currency, using the correct thousand and decimal separators.
8+
Format a numeric value as Brazilian currency (R$).
139
1410
Args:
15-
value (float or Decimal): The numeric value to be formatted.
11+
value: The numeric value to format. Accepts float, int, str, or Decimal.
1612
1713
Returns:
18-
str or None: A string formatted as Brazilian currency, or None if the input is invalid.
14+
Formatted currency string (e.g., "R$ 1.234,56") or None if invalid.
1915
2016
Example:
2117
>>> format_currency(1234.56)
22-
"R$ 1.234,56"
18+
'R$ 1.234,56'
2319
>>> format_currency(0)
24-
"R$ 0,00"
20+
'R$ 0,00'
2521
>>> format_currency(-9876.54)
26-
"R$ -9.876,54"
27-
>>> format_currency(None)
28-
None
29-
>>> format_currency("not a number")
22+
'R$ -9.876,54'
23+
>>> format_currency("invalid")
3024
None
3125
"""
32-
3326
try:
3427
decimal_value = Decimal(value)
3528
formatted_value = (
3629
f"R$ {decimal_value:,.2f}".replace(",", "_")
3730
.replace(".", ",")
3831
.replace("_", ".")
3932
)
40-
4133
return formatted_value
42-
except InvalidOperation:
34+
except (InvalidOperation, TypeError, ValueError):
4335
return None
4436

4537

46-
def convert_real_to_text(amount: Decimal) -> Union[str, None]:
38+
def convert_real_to_text(amount: Decimal | float | int | str) -> str | None:
4739
"""
48-
Converts a given monetary value in Brazilian Reais to its textual representation.
49-
50-
This function takes a decimal number representing a monetary value in Reais
51-
and converts it to a string with the amount written out in Brazilian Portuguese. It
52-
handles both the integer part (Reais) and the fractional part (centavos), respecting
53-
the correct grammar for singular and plural cases, as well as special cases like zero
54-
and negative values.
40+
Convert a monetary value in Brazilian Reais to textual representation.
5541
5642
Args:
57-
amount (decimal): The monetary value to be converted into text.
58-
- The integer part represents Reais.
59-
- The decimal part represents centavos.
60-
- 2 decimal places
43+
amount: Monetary value to convert. Accepts Decimal, float, int, or str.
6144
6245
Returns:
63-
str: A string with the monetary value written out in Brazilian Portuguese.
64-
- Returns "Zero reais" for a value of 0.00.
65-
- Returns None if the amount is invalid or absolutely greater than 1 quadrillion.
66-
- Handles negative values, adding "Menos" at the beginning of the string.
46+
Textual representation in Brazilian Portuguese, or None if invalid.
6747
68-
Limitations:
69-
- This function may lose precision by ±1 cent for cases where the absolute value
70-
is beyond trillions due to floating-point rounding errors.
48+
Note:
49+
- Values are rounded down to 2 decimal places
50+
- Maximum supported value is 1 quadrillion reais
51+
- Negative values are prefixed with "Menos"
7152
7253
Example:
7354
>>> convert_real_to_text(1523.45)
74-
"Mil, quinhentos e vinte e três reais e quarenta e cinco centavos"
55+
'Mil, quinhentos e vinte e três reais e quarenta e cinco centavos'
7556
>>> convert_real_to_text(1.00)
76-
"Um real"
57+
'Um real'
7758
>>> convert_real_to_text(0.50)
78-
"Cinquenta centavos"
59+
'Cinquenta centavos'
7960
>>> convert_real_to_text(0.00)
80-
"Zero reais"
81-
>>> convert_real_to_text(-50.25)
82-
"Menos cinquenta reais e vinte e cinco centavos"
61+
'Zero reais'
8362
"""
84-
8563
try:
8664
amount = Decimal(str(amount)).quantize(
8765
Decimal("0.01"), rounding=ROUND_DOWN
8866
)
89-
except InvalidOperation:
67+
except (InvalidOperation, TypeError, ValueError):
9068
return None
9169

9270
if amount.is_nan() or amount.is_infinite():

tests/test_currency.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ def test_when_value_is_negative(self):
1515
assert format_currency(-123236.70) == "R$ -123.236,70"
1616

1717
def test_when_value_is_zero(self):
18-
print(format_currency(0))
1918
assert format_currency(0) == "R$ 0,00"
2019

2120
def test_value_decimal_replace_rounding(self):

0 commit comments

Comments
 (0)