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.

classification
Title: str.format and f-string divergence
Type: enhancement Stage: resolved
Components: Documentation Versions: Python 3.9
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: docs@python Nosy List: barry, brett.cannon, docs@python, eric.smith, larry, lisroach, lukasz.langa, rhettinger, serhiy.storchaka, thatch
Priority: normal Keywords:

Created on 2019-06-19 17:36 by thatch, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (6)
msg346065 - (view) Author: Tim Hatch (thatch) * Date: 2019-06-19 17:36
TL;DR

f"{x+2}" and f"{x=}" do something sensible.
"{x+2}".format(x=1) and "{x=}".format(x=1) raise KeyError.
f"{0.1}" and "{0.1}".format(...) are different.

Having had a feature request to be able to codemod f-strings[1] and just learning about issue36817[2] last night, I went digging into how these are parsed in the standard library to be able to reuse that.

str.format, string.Formatter, and the _string module can only parse literal keys, not expressions, despite appearing to take the same syntax as f-strings.  I'm happy to contribute code to change this, but unsure if it's considered a bug or feature (now that we're past feature freeze for 3.8).  I would love to see these converge to prevent confusion and let us document in just one place.

The {} and {1} style are still exceptional.

We already parse expressions and the "=" suffix acceptably,

>>> list(_string.formatter_parser("{1+1}"))
[('', '1+1', '', None)]
>>> list(_string.formatter_parser("{(x)}"))
[('', '(x)', '', None)]
>>> list(_string.formatter_parser("{x=!r:1}"))
[('', 'x=', '1', 'r')]
>>> list(_string.formatter_parser("{ x = }"))
[('', ' x = ', '', None)]

But the consumers would need to check for /=\s*$/ and call eval on the items in formatter_field_name_split.  (I lack a good heuristic, maybe we eval every time unless it's strictly numeric?)

It would also break unusual uses like these in the name of unification

>>> "{1+1}".format(**{"1+1": "zzz"})
'zzz'

and

>>> class T:
...   pass
... 
>>> setattr(T, "0", "zero")
>>> f"{T.0}"
  File "<fstring>", line 1
    (T.0)
       ^
SyntaxError: invalid syntax
>>> "{0.0}".format(T)
'zero'

[1] https://github.com/facebookincubator/Bowler/issues/87
[2] incorrectly listed in Misc/NEWS.d/3.8.0b1.rst as issue36774 btw
msg346066 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-06-19 17:46
> str.format, string.Formatter, and the _string module can only
> parse literal keys, not expressions, despite appearing to take the
> same syntax as f-strings.  I'm happy to contribute code to change
> this, but unsure if it's considered a bug or feature (now that we're
> past feature freeze for 3.8).  I would love to see these converge to
> prevent confusion and let us document in just one place.

It's a feature that str.format does not accept expressions. If it did, it would:
1: require compiler support (eval isn't good enough)
2: be a security hole magnet

I think both of these are sufficiently strong arguments that I won't support making expressions work in str.format().

For the security hole, you don't want:

user_provided_string.format()

to be able to execute arbitrary code. You're basically eval-ing (parts of) strings, and everyone would suddenly have to audit all of their code to make sure there are no security holes exposed.
msg346070 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-06-19 18:37
I concur with Eric.  This differences are there by design.  The technical and security reasons are both compelling.
msg346073 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2019-06-19 19:01
I also agree with Eric's assessment.

Thanks for the idea, Tim, but I'm closing this as rejected.
msg346077 - (view) Author: Tim Hatch (thatch) * Date: 2019-06-19 19:23
ok, I suppose it's just documentation then.
msg346109 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-06-20 08:24
I've fixed the bpo number in Misc/NEWS.d/3.8.0b1.rst. Thanks for reporting that.
History
Date User Action Args
2022-04-11 14:59:16adminsetgithub: 81522
2019-06-20 08:24:56eric.smithsetmessages: + msg346109
2019-06-19 19:23:52thatchsetnosy: + docs@python
messages: + msg346077

assignee: docs@python
components: + Documentation, - Library (Lib)
2019-06-19 19:01:44brett.cannonsetstatus: open -> closed

nosy: + brett.cannon
messages: + msg346073

resolution: rejected
stage: resolved
2019-06-19 18:37:43rhettingersetnosy: + rhettinger
messages: + msg346070
2019-06-19 17:46:59eric.smithsetmessages: + msg346066
versions: - Python 3.8
2019-06-19 17:36:46thatchcreate