New submission from Michael Amrhein <mich...@adrhinum.de>:

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.

----------
messages: 358561
nosy: mamrhein
priority: normal
severity: normal
status: open
title: Numeric formatting inconsistent between int, float and Decimal
type: behavior
versions: Python 3.6, Python 3.7, Python 3.8

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue39077>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to