Opened 9 months ago

Closed 4 months ago

Last modified 12 days ago

#35816 closed Bug (fixed)

Django Template Language doesn't support all float literals

Reported by: Lily Foote Owned by: Hailey Johnson
Component: Template system Version: 5.1
Severity: Normal Keywords:
Cc: 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

When parsing arguments to filters, Django converts numeric literals to float or int, but in the case of scientific notation for float this is incomplete:

>>> from django.template.base import Template
>>> from django.template.engine import Engine
>>> 5.2e3
5200.0
>>> Template("{{ foo|default:5.2e3 }}", engine=e)
<Template template_string="{{ foo|default:5.2e3...">
>>> 5.2e-3
0.0052
>>> Template("{{ foo|default:5.2e-3 }}", engine=e)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/lily/.local/share/lilyenv/virtualenvs/django-rusty-templates/3.12/lib/python3.12/site-packages/django/template/base.py", line 154, in __init__
    self.nodelist = self.compile_nodelist()
                    ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lily/.local/share/lilyenv/virtualenvs/django-rusty-templates/3.12/lib/python3.12/site-packages/django/template/base.py", line 196, in compile_nodelist
    nodelist = parser.parse()
               ^^^^^^^^^^^^^^
  File "/home/lily/.local/share/lilyenv/virtualenvs/django-rusty-templates/3.12/lib/python3.12/site-packages/django/template/base.py", line 489, in parse
    raise self.error(token, e)
  File "/home/lily/.local/share/lilyenv/virtualenvs/django-rusty-templates/3.12/lib/python3.12/site-packages/django/template/base.py", line 487, in parse
    filter_expression = self.compile_filter(token.contents)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lily/.local/share/lilyenv/virtualenvs/django-rusty-templates/3.12/lib/python3.12/site-packages/django/template/base.py", line 605, in compile_filter
    return FilterExpression(token, self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lily/.local/share/lilyenv/virtualenvs/django-rusty-templates/3.12/lib/python3.12/site-packages/django/template/base.py", line 706, in __init__
    raise TemplateSyntaxError(
django.template.exceptions.TemplateSyntaxError: Could not parse the remainder: '-3' from 'foo|default:5.2e-3'

I couldn't actually find the documentation for Django's handling of numeric literals in templates, so this may be an undocumented implementation detail. If so, perhaps deprecating scientific notation would be appropriate. Otherwise, we should support this case.

Change History (24)

comment:1 by Lily Foote, 9 months ago

Version: 5.05.1

comment:2 by Aryaman, 9 months ago

Owner: set to Aryaman
Status: newassigned

I am beginner in os , Giving this a try

comment:3 by Sarah Boyce, 9 months ago

Component: UncategorizedTemplate system
Triage Stage: UnreviewedAccepted

Thank you! We try to support scientific numbers so we should fix this.
I believe their is an issue with the regex, this might work

  • django/template/base.py

    diff --git a/django/template/base.py b/django/template/base.py
    index ee2e145c04..e0d032f688 100644
    a b filter_raw_string = r"""  
    640640         )?
    641641 )""" % {
    642642    "constant": constant_string,
    643     "num": r"[-+.]?\d[\d.e]*",
     643    "num": r"[-+.]?\d[\d.e-]*",
    644644    "var_chars": r"\w\.",
    645645    "filter_sep": re.escape(FILTER_SEPARATOR),

Will need a test

comment:4 by Sarah Boyce, 9 months ago

Type: UncategorizedBug

comment:5 by IronJam, 5 months ago

Yeah it looks like a regex error. I can code a regression test and make a pr.

comment:6 by IronJam, 5 months ago

Owner: changed from Aryaman to IronJam

comment:8 by IronJam, 5 months ago

Resolution: fixed
Status: assignedclosed

comment:9 by IronJam, 5 months ago

Resolution: fixed
Status: closednew

comment:10 by Antoliny, 5 months ago

Has patch: set

comment:11 by Sarah Boyce, 4 months ago

Patch needs improvement: set

comment:12 by Hailey Johnson, 4 months ago

Patch needs improvement: unset

comment:13 by Hailey Johnson, 4 months ago

Owner: changed from IronJam to Hailey Johnson
Status: newassigned

comment:15 by Sarah Boyce, 4 months ago

Patch needs improvement: set

comment:16 by Sarah Boyce, 4 months ago

Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

comment:17 by GitHub <noreply@…>, 4 months ago

Resolution: fixed
Status: assignedclosed

In 5183f7c2:

Fixed #35816 -- Handled parsing of scientific notation in DTL. (#19213)

  • Refs #35816 -- Improved test coverage of FilterExpression.
  • Fixed #35816 -- Made FilterExpression parse scientific numbers.

Co-authored-by: Sarah Boyce <42296566+sarahboyce@…>

comment:18 by Sarah Boyce, 4 months ago

Note that despite selecting "rebase and merge" on the PR, this appears to be squashed merged. I have now disabled the squash merge on the project.

comment:19 by Jon Banafato, 3 weeks ago

I have a question about template behavior that was changed by this feature (please let me know if I should post this as a new ticket instead of continuing conversation here). While investigating CI test failures for django-hosts, I observed that Django no longer throws a TemplateSyntaxError for template variable names containing dashes and instead appears to treat them as regular template variable names. I did not see any notes in the template language documentation or the templates section of the release notes for 6.0. I believe this change was introduced by the commit associated with this issue, and I've included an example of the behavioral change below.

On commit 8df5ce80d26824ce72af41edc03275d435de9432, the following code fails with a TemplateSyntaxError as expected.

>>> from django.template import Template, Context
>>> template = Template("Hello, {{ first-name }}")
Traceback (most recent call last):
...
django.template.exceptions.TemplateSyntaxError: Could not parse the remainder: '-name' from 'first-name'

On commit 5183f7c287a9a5d61ca1103b55166cda5, the following code parses the template and renders the first-name provided.

>>> from django.template import Template, Context
>>> template = Template("Hello, {{ first-name }}")
>>> template.render(Context({"first-name": "Jon"}))
'Hello, Jon'

Does this warrant a new ticket for a behavior and / or documentation change? I'd be happy to help where possible, but I'm not very familiar with this change or the Django development process in general, so I am looking for guidance. Thanks!

comment:20 by Hailey Johnson, 3 weeks ago

Hi, you're right that this ticket did change that behavior!

I'm happy to add documentation if we decide to keep it as is, I would argue that if we want to revert the behavior, it shouldn't be handled where it was before because we don't differentiate from variable names and numeric values at that point.

in reply to:  20 comment:21 by Jon Banafato, 3 weeks ago

Thanks for the quick response! The template variable name behavior seems like a rather impactful change compared to the state scope of supporting float literals. I wanted to comment here mostly so that the change didn't go unintended and unnoticed.

comment:22 by Hailey Johnson, 2 weeks ago

That makes sense! I'd be glad to follow-up either way. I think the '-' character was neither explicitly included or excluded in valid variable naming (unlike, e.g. whitespace characters are explicitly prohibiting and underscores are explicitly allowed).

comment:23 by Baptiste Mispelon, 2 weeks ago

Thanks for flagging this Jon! It's always great when bugs get noticed ahead of a release 😅

This looks like a bug to me, so I've opened #36465 (which I marked as a release blocker since it's a breaking change in behavior).

comment:24 by Sarah Boyce <42296566+sarahboyce@…>, 12 days ago

In 22506b2:

Fixed #36465, Refs #35816 -- Disallowed '+' and '-' characters in template variable names.

Regression in 5183f7c287a9a5d61ca1103b55166cda52d9c647.

Thank you to Jon Banafato and Baptiste Mispelon for the report.

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