Repository: jmoiron/humanize

Issue:
intcomma() variant needed to handle money
When using intcomma on a dollar value like 14308.40, I get '14,308.4'.

It would be nice to have a moneycomma(14308.40,2) which gives me '14,308.40'.


Discussion:

Patch:
diff --git a/src/humanize/number.py b/src/humanize/number.py
index f57588e..013448e 100644
--- a/src/humanize/number.py
+++ b/src/humanize/number.py
@@ -35,11 +35,19 @@ def ordinal(value):
     return "%d%s" % (value, t[value % 10])
 
 
-def intcomma(value):
+def intcomma(value, ndigits=None):
     """Converts an integer to a string containing commas every three digits.
-    For example, 3000 becomes '3,000' and 45000 becomes '45,000'.  To maintain
-    some compatibility with Django's intcomma, this function also accepts
-    floats."""
+
+    For example, 3000 becomes "3,000" and 45000 becomes "45,000". To maintain some
+    compatibility with Django's intcomma, this function also accepts floats.
+
+    Args:
+        value (int, float, string): Integer or float to convert.
+        ndigits (int, None): digits of precision for rounding after the decimal point.
+
+    Returns:
+        str: string containing commas every three digits.
+    """
     try:
         if isinstance(value, str):
             float(value.replace(",", ""))
@@ -47,7 +55,12 @@ def intcomma(value):
             float(value)
     except (TypeError, ValueError):
         return value
-    orig = str(value)
+
+    if ndigits:
+        orig = "{0:.{1}f}".format(value, ndigits)
+    else:
+        orig = str(value)
+
     new = re.sub(r"^(-?\d+)(\d{3})", r"\g<1>,\g<2>", orig)
     if orig == new:
         return new


Test patch:
diff --git a/tests/test_number.py b/tests/test_number.py
index cdb0d7c..c7cbc66 100644
--- a/tests/test_number.py
+++ b/tests/test_number.py
@@ -30,25 +30,36 @@ def test_ordinal(test_input, expected):
 
 
 @pytest.mark.parametrize(
-    "test_input, expected",
+    "test_args, expected",
     [
-        (100, "100"),
-        (1000, "1,000"),
-        (10123, "10,123"),
-        (10311, "10,311"),
-        (1000000, "1,000,000"),
-        (1234567.25, "1,234,567.25"),
-        ("100", "100"),
-        ("1000", "1,000"),
-        ("10123", "10,123"),
-        ("10311", "10,311"),
-        ("1000000", "1,000,000"),
-        ("1234567.1234567", "1,234,567.1234567"),
-        (None, None),
+        ([100], "100"),
+        ([1000], "1,000"),
+        ([10123], "10,123"),
+        ([10311], "10,311"),
+        ([1000000], "1,000,000"),
+        ([1234567.25], "1,234,567.25"),
+        (["100"], "100"),
+        (["1000"], "1,000"),
+        (["10123"], "10,123"),
+        (["10311"], "10,311"),
+        (["1000000"], "1,000,000"),
+        (["1234567.1234567"], "1,234,567.1234567"),
+        ([None], None),
+        ([14308.40], "14,308.4"),
+        ([14308.40, None], "14,308.4"),
+        ([14308.40, 1], "14,308.4"),
+        ([14308.40, 2], "14,308.40"),
+        ([14308.40, 3], "14,308.400"),
+        ([1234.5454545], "1,234.5454545"),
+        ([1234.5454545, None], "1,234.5454545"),
+        ([1234.5454545, 1], "1,234.5"),
+        ([1234.5454545, 2], "1,234.55"),
+        ([1234.5454545, 3], "1,234.545"),
+        ([1234.5454545, 10], "1,234.5454545000"),
     ],
 )
-def test_intcomma(test_input, expected):
-    assert humanize.intcomma(test_input) == expected
+def test_intcomma(test_args, expected):
+    assert humanize.intcomma(*test_args) == expected
 
 
 def test_intword_powers():