Opened 21 months ago

Closed 21 months ago

Last modified 21 months ago

#34363 closed Bug (fixed)

floatformat() crashes on "0.0000"

Reported by: Takis Issaris Owned by: Takis Issaris
Component: Template system Version: 4.2
Severity: Release blocker Keywords: filters
Cc: David Wobrock Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Similar to #34272 the current Django code (both 4.2b1 and latest git) crash on using the floatformat template filter with
0 values.

from decimal import Decimal
from django.template.defaultfilters import floatformat

floatformat('0.0000', 2)
floatformat(Decimal('0.0000'), 2)

Both throw ValueError: valid range for prec is [1, MAX_PREC]

Using git bisect I tracked the bug to commit 08c5a787262c1ae57f6517d4574b54a5fcaad124.

When one uses "0.0000": floatformat:2 the current code results in a precision of 0 which is
not allowed:

tupl = d.as_tuple()                   # with d being "0.0000" returns (sign=0,digits=(0,),exponent=-4)
units = len(tupl[1])                  # equals 1
units += -tupl[2] if m else tupl[2]   # 1 + (-4)
prec = abs(p) + units + 1             # 2 (number of requested decimals) + (-3) + 1 equals 0

rounded_d = d.quantize(exp, ROUND_HALF_UP, Context(prec=prec))

Attachments (1)

ic-20230222T1222-django-floatformat.diff (1.4 KB ) - added by Takis Issaris 21 months ago.
Fix floatformat for zero values

Download all attachments as: .zip

Change History (8)

by Takis Issaris, 21 months ago

Fix floatformat for zero values

comment:1 by Takis Issaris, 21 months ago

A minimal patch is available on this branch on GitHub:
https://github.com/takis/django/tree/ticket_34363

comment:2 by Mariusz Felisiak, 21 months ago

Cc: David Wobrock added
Owner: changed from nobody to Takis Issaris
Status: newassigned
Triage Stage: UnreviewedAccepted

Thanks for the report! Please submit PR via GitHub.

comment:3 by Takis Issaris, 21 months ago

Thanks for the quick response! I've created a pull request on GitHub.

comment:4 by Takis Issaris, 21 months ago

My actual code was different, but I had tried to keep the patch-size minimal.

The code I was using in a separate test-file in which I factored out the get_precision function for easier
testing. But I figured this might not be OK for performance reasons for Django.

def get_precision(d: Decimal, p: int) -> int:
    """Return the number of significant digits for a decimal number.
    
    d: the decimal number
    p: the number of decimals requested
    """
    if d == 0:
        # If the number is zero, the precision is the number of decimals requested
        return p
    _, digits, exponent = d.as_tuple()
    units = len(digits)  # total number of digits
    before_comma = units + exponent

    # adding 1 for possible rounding up e.g. (99.99, 1) -> 100.0 needs 4 digits
    prec = abs(p) + before_comma + 1 
    return max(1, prec)   # 1 is the minimum precision for Decimal.quantize()
Last edited 21 months ago by Takis Issaris (previous) (diff)

comment:5 by Mariusz Felisiak, 21 months ago

Triage Stage: AcceptedReady for checkin

comment:6 by GitHub <noreply@…>, 21 months ago

Resolution: fixed
Status: assignedclosed

In dcd97469:

Fixed #34363 -- Fixed floatformat crash on zero with trailing zeros.

Regression in 08c5a787262c1ae57f6517d4574b54a5fcaad124.
Follow up to 4b066bde692078b194709d517b27e55defae787c.

comment:7 by Mariusz Felisiak <felisiak.mariusz@…>, 21 months ago

In ce69dba0:

[4.2.x] Fixed #34363 -- Fixed floatformat crash on zero with trailing zeros.

Regression in 08c5a787262c1ae57f6517d4574b54a5fcaad124.
Follow up to 4b066bde692078b194709d517b27e55defae787c.
Backport of dcd974698301a38081c141ccba6dcafa5ed2c80e from main

Note: See TracTickets for help on using tickets.
Back to Top