Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/utils/numberformat.py: 5%
54 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from decimal import Decimal
3from django.conf import settings
4from django.utils.safestring import mark_safe
7def format(
8 number,
9 decimal_sep,
10 decimal_pos=None,
11 grouping=0,
12 thousand_sep="",
13 force_grouping=False,
14 use_l10n=None,
15):
16 """
17 Get a number (as a number or string), and return it as a string,
18 using formats defined as arguments:
20 * decimal_sep: Decimal separator symbol (for example ".")
21 * decimal_pos: Number of decimal positions
22 * grouping: Number of digits in every group limited by thousand separator.
23 For non-uniform digit grouping, it can be a sequence with the number
24 of digit group sizes following the format used by the Python locale
25 module in locale.localeconv() LC_NUMERIC grouping (e.g. (3, 2, 0)).
26 * thousand_sep: Thousand separator symbol (for example ",")
27 """
28 use_grouping = (
29 use_l10n or (use_l10n is None and settings.USE_L10N)
30 ) and settings.USE_THOUSAND_SEPARATOR
31 use_grouping = use_grouping or force_grouping
32 use_grouping = use_grouping and grouping != 0
33 # Make the common case fast
34 if isinstance(number, int) and not use_grouping and not decimal_pos:
35 return mark_safe(number)
36 # sign
37 sign = ""
38 # Treat potentially very large/small floats as Decimals.
39 if isinstance(number, float) and "e" in str(number).lower():
40 number = Decimal(str(number))
41 if isinstance(number, Decimal):
43 if decimal_pos is not None:
44 # If the provided number is too small to affect any of the visible
45 # decimal places, consider it equal to '0'.
46 cutoff = Decimal("0." + "1".rjust(decimal_pos, "0"))
47 if abs(number) < cutoff:
48 number = Decimal("0")
50 # Format values with more than 200 digits (an arbitrary cutoff) using
51 # scientific notation to avoid high memory usage in {:f}'.format().
52 _, digits, exponent = number.as_tuple()
53 if abs(exponent) + len(digits) > 200:
54 number = "{:e}".format(number)
55 coefficient, exponent = number.split("e")
56 # Format the coefficient.
57 coefficient = format(
58 coefficient,
59 decimal_sep,
60 decimal_pos,
61 grouping,
62 thousand_sep,
63 force_grouping,
64 use_l10n,
65 )
66 return "{}e{}".format(coefficient, exponent)
67 else:
68 str_number = "{:f}".format(number)
69 else:
70 str_number = str(number)
71 if str_number[0] == "-":
72 sign = "-"
73 str_number = str_number[1:]
74 # decimal part
75 if "." in str_number:
76 int_part, dec_part = str_number.split(".")
77 if decimal_pos is not None:
78 dec_part = dec_part[:decimal_pos]
79 else:
80 int_part, dec_part = str_number, ""
81 if decimal_pos is not None:
82 dec_part = dec_part + ("0" * (decimal_pos - len(dec_part)))
83 dec_part = dec_part and decimal_sep + dec_part
84 # grouping
85 if use_grouping:
86 try:
87 # if grouping is a sequence
88 intervals = list(grouping)
89 except TypeError:
90 # grouping is a single value
91 intervals = [grouping, 0]
92 active_interval = intervals.pop(0)
93 int_part_gd = ""
94 cnt = 0
95 for digit in int_part[::-1]:
96 if cnt and cnt == active_interval:
97 if intervals:
98 active_interval = intervals.pop(0) or active_interval
99 int_part_gd += thousand_sep[::-1]
100 cnt = 0
101 int_part_gd += digit
102 cnt += 1
103 int_part = int_part_gd[::-1]
104 return sign + int_part + dec_part