This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author mamrhein
Recipients mamrhein
Date 2019-12-17.17:48:02
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1576604882.94.0.74204520541.issue39077@roundup.psfhosted.org>
In-reply-to
Content
The __format__ methods of int, float and Decimal (C and Python implementation) do not interpret the Format Specification Mini-Language in the same way:

>>> import decimal as cdec
... cdec.__file__
...
'/usr/lib64/python3.6/decimal.py'
>>> import _pydecimal as pydec
... pydec.__file__
...
'/usr/lib64/python3.6/_pydecimal.py'

>>> i = -1234567890
... f = float(i)
... d = cdec.Decimal(i)
... p = pydec.Decimal(i)
...
>>> # Case 1: no fill, no align, no zeropad
... fmt = "28,"
>>> format(i, fmt)
'              -1,234,567,890'
>>> format(f, fmt)
'            -1,234,567,890.0'
>>> format(d, fmt)
'              -1,234,567,890'
>>> format(p, fmt)
'              -1,234,567,890'

>>> # Case 2: no fill, no align, but zeropad
... fmt = "028,"
>>> format(i, fmt)
'-000,000,000,001,234,567,890'
>>> format(f, fmt)
'-0,000,000,001,234,567,890.0'
>>> format(d, fmt)
'-000,000,000,001,234,567,890'
>>> format(p, fmt)
'-000,000,000,001,234,567,890'

>>> # Case 3: no fill, but align '>' + zeropad
... fmt = ">028,"
>>> format(i, fmt)
'00000000000000-1,234,567,890'
>>> format(f, fmt)
'000000000000-1,234,567,890.0'
>>> format(d, fmt)
ValueError: invalid format string
>>> format(p, fmt)
ValueError: Alignment conflicts with '0' in format specifier: >028,

>>> # Case 4: no fill, but align '=' + zeropad
... fmt = "=028,"
>>> format(i, fmt)
'-000,000,000,001,234,567,890'
>>> format(f, fmt)
'-0,000,000,001,234,567,890.0'
>>> format(d, fmt)
ValueError: invalid format string
>>> format(p, fmt)
ValueError: Alignment conflicts with '0' in format specifier: =028,

>>> # Case 5: fill '0', align '=' + zeropad
... fmt = "0=028,"
>>> format(i, fmt)
'-000,000,000,001,234,567,890'
>>> format(f, fmt)
'-0,000,000,001,234,567,890.0'
>>> format(d, fmt)
ValueError: invalid format string
>>> format(p, fmt)
ValueError: Fill character conflicts with '0' in format specifier: 0=028,

>>> # Case 6: fill ' ', align '=' + zeropad
... fmt = " =028,"
>>> format(i, fmt)
'-              1,234,567,890'
>>> format(f, fmt)
'-            1,234,567,890.0'
>>> format(d, fmt)
ValueError: invalid format string
>>> format(p, fmt)
ValueError: Fill character conflicts with '0' in format specifier:  =028,

>>> # Case 7: fill ' ', align '>' + zeropad
... fmt = " >028,"
>>> format(i, fmt)
'              -1,234,567,890'
>>> format(f, fmt)
'            -1,234,567,890.0'
>>> format(d, fmt)
ValueError: invalid format string
>>> format(p, fmt)
ValueError: Fill character conflicts with '0' in format specifier:  >028,

>>> # Case 8: fill ' ', no align, but zeropad
... fmt = " 028,"
>>> format(i, fmt)
'-000,000,000,001,234,567,890'
>>> format(f, fmt)
'-0,000,000,001,234,567,890.0'
>>> format(d, fmt)
'-000,000,000,001,234,567,890'
>>> format(p, fmt)
'-000,000,000,001,234,567,890'

>>> # Case 9: fill '_', no align, but zeropad
... fmt = "_028,"
>>> format(i, fmt)
ValueError: Invalid format specifier
>>> format(f, fmt)
ValueError: Invalid format specifier
>>> format(d, fmt)
ValueError: invalid format string
>>> format(p, fmt)
ValueError: Invalid format specifier: _028,

>>> # Case 10: fill '_', no align, no zeropad
... fmt = "_28,"
>>> format(i, fmt)
ValueError: Invalid format specifier
>>> format(f, fmt)
ValueError: Invalid format specifier
>>> format(d, fmt)
ValueError: Invalid format string
>>> format(p, fmt)
ValueError: Invalid format specifier: _28,

>>> # Case 11: fill '0', align '>', no zeropad
... fmt = "0>28,"
>>> format(i, fmt)
'00000000000000-1,234,567,890'
>>> format(f, fmt)
'000000000000-1,234,567,890.0'
>>> format(d, fmt)
'00000000000000-1,234,567,890'
>>> format(p, fmt)
'00000000000000-1,234,567,890'

>>> # Case 12: fill '0', align '<', no zeropad
... fmt = "0<28,"
>>> format(i, fmt)
'-1,234,567,89000000000000000'
>>> format(f, fmt)
'-1,234,567,890.0000000000000'
>>> format(d, fmt)
'-1,234,567,89000000000000000'
>>> format(p, fmt)
'-1,234,567,89000000000000000'

>>> # Case 13: fixed-point notation w/o precision
... fmt = "f"
>>> format(f, fmt)
'-1234567890.000000'
>>> format(d, fmt)
'-1234567890'
>>> format(p, fmt)
'-1234567890'

Case 1 & 2:
For a format string not giving a type ("None") the spec says: "Similar to 'g', except that fixed-point notation, when used, has at least one digit past the decimal point." float does follow this rule, Decimal does not.
While this may be regarded as reasonable, it should be noted in the doc. 

Cases 3 to 7:
Both implementations of Decimal do not allow to combine align and zeropad, while int and float do. When also fill is given, int and float ignore zeropad, but use '0' instead of ' ' (default), if not. 
(For an exception see the following case.)
The spec says: "When no explicit alignment is given, preceding the width field by a zero ('0') character enables sign-aware zero-padding for numeric types. This is equivalent to a fill character of '0' with an alignment type of '='." That does not explicitly give a rule for align + zeropad together, but IMHO it suggests to use zeropad *only* if no align is given and that it should *not* overwrite the default fill ' '.

Cases 8 - 10:
The syntax given by the spec IMHO says: no fill without align! There is no mention of an exception for a blank as fill.

Case 11 & 12:
While all implementation "agree" here, combining '0' as fill with align other than '=' gives really odd results.
See also https://bugs.python.org/issue17247.

Case 13:
For fixed-point notation the spec says: "The default precision is 6." float does follow this rule, Decimal does not.
While this may be regarded as reasonable, it should be noted in the doc.
History
Date User Action Args
2019-12-17 17:48:03mamrheinsetrecipients: + mamrhein
2019-12-17 17:48:02mamrheinsetmessageid: <1576604882.94.0.74204520541.issue39077@roundup.psfhosted.org>
2019-12-17 17:48:02mamrheinlinkissue39077 messages
2019-12-17 17:48:02mamrheincreate