classification
Title: locale.format() and locale.format_string() cast Decimals to float
Type: enhancement Stage: patch review
Components: Interpreter Core, Library (Lib) Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: ced, eric.smith, jemerton
Priority: normal Keywords: patch

Created on 2018-08-01 20:22 by jemerton, last changed 2019-08-14 11:28 by ced.

Pull Requests
URL Status Linked Edit
PR 15275 open ced, 2019-08-14 11:25
Messages (5)
msg322885 - (view) Author: James Emerton (jemerton) * Date: 2018-08-01 20:22
We use locale.format('%.2f', x, True) to convert Decimal values to strings for display. Unfortunately, the locale module is using %-formatting to generate the initial string before applying locale specific formatting. As a result, any value which cannot be accurately represented as a float will produce incorrect results.

I've built some formatting that uses new-style string formatting (and some internal locale functions) which corrects the problem.

Unfortunately, making this change in the locale module would require converting the input format string to the new syntax, so '%.2f' would become '{:.2f}'.

See also #33731
msg322903 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-08-02 00:40
Would my suggestion in #33731 of adding another letter in the format spec for float and decimal.Decimal solve your problem? I guess if you're using monetary=True you'd need two additional letters: like 'f' but locale aware, and like 'f' but locale aware and monetary=True.  Maybe 'l' and 'L' for these? In this case, there would be no changes to the locale module.

I don't see any good way of using new-style formatting without changing float.__format__ and decimal.Decimal.__format__.
msg322904 - (view) Author: James Emerton (jemerton) * Date: 2018-08-02 00:48
Certainly adding another letter to the format spec would solve my issue and would in fact be somewhat preferable to using local.format directly.

I think this could be fixed in the locale module by transforming the format spec and using new-style formatting, but I'm not familiar enough with the corner cases to know if its practical to cover all the possible cases; particularly those coming from format_string().
msg323120 - (view) Author: James Emerton (jemerton) * Date: 2018-08-04 22:14
It looks like a bot got a bit excited when I mentioned this issue in the PR for bpo-33731. I unlinked the PR but this issue still got flagged for review.
msg349683 - (view) Author: Cédric Krier (ced) * Date: 2019-08-14 11:28
I think we can solve this issue like I solved issue13918 by providing a locale.localize() method which does the formatting as locale.format_string does but using the already formatted string.

I created PR-15275 which implements it and also use the new format in locale.currency as it is highly probable that currency will be used with Decimal.
History
Date User Action Args
2019-08-14 11:28:50cedsetnosy: + ced
messages: + msg349683
2019-08-14 11:25:09cedsetpull_requests: + pull_request14997
2018-08-04 22:14:21jemertonsetmessages: + msg323120
2018-08-04 22:12:52jemertonsetpull_requests: - pull_request8166
2018-08-04 22:07:37jemertonsetkeywords: + patch
stage: patch review
pull_requests: + pull_request8166
2018-08-02 00:48:39jemertonsetmessages: + msg322904
2018-08-02 00:40:06eric.smithsettype: enhancement
messages: + msg322903
components: + Interpreter Core
versions: - Python 3.6, Python 3.7
2018-08-02 00:29:02eric.smithsetnosy: + eric.smith
2018-08-01 20:22:51jemertoncreate