classification
Title: :s formatting broken for objects without __format__
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.6, Python 3.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder: object.__format__ should reject format strings
View: 7994
Assigned To: eric.smith Nosy List: Jason Spencer, eric.smith, martin.panter
Priority: normal Keywords:

Created on 2018-08-18 00:18 by Jason Spencer, last changed 2018-08-22 15:44 by eric.smith. This issue is now closed.

Messages (6)
msg323688 - (view) Author: Jason Spencer (Jason Spencer) Date: 2018-08-18 00:18
Objects with __str__ but WITHOUT __format__ are string-convertible and default-to-str formattable.  But the explicit use of '{:s}' as a format string fails to format these objects as expected.  Either it is no longer the case that '{}' and '{:s}' are equivalent format strings, or formatting for {:s} is broken.  Users would not expect the following to be true.

(Tested in 3.5.3 and 3.6.  Maybe be the same in later releases.)

Python 3.5.3 (default, Jan 19 2017, 14:11:04) 
[GCC 6.3.0 20170118] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class Coord:
...   def __init__(self, a, b):
...     self.a=a
...     self.b=b
...   def __str__(self):
...     return '{:d}:{:d}'.format(self.a, self.b)
... 
>>> c = Coord(3,4)
>>> str(c)
'3:4'
>>> '{:s}'.format(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported format string passed to Coord.__format__
>>> '{}'.format(c)
'3:4'
>>> '{!s:s}'.format(c)
'3:4'
>>>
msg323689 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2018-08-18 04:59
It looks like you are describing the result of Issue 7994. Documentation:

https://docs.python.org/release/3.5.3/reference/datamodel.html#object.__format__
https://docs.python.org/release/3.5.3/whatsnew/3.4.html#api-and-feature-removals
msg323719 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-08-18 17:12
I agree this is the desired behavior, and not a bug.

Because you are not specifying a __format__ in your class, object.__format__ is being called. By design, it does not understand any formatting specifiers, instead reserving them for your class to implement. "!s" is the correct way to convert your type to a string. Either that, or add a __format__ that understands "s".

Note that not all types understand "s", for example, datetime.
msg323798 - (view) Author: Jason Spencer (Jason Spencer) Date: 2018-08-20 16:26
Then I would argue that it is at least a documentation bug.  The 3.6 format
spec mini language still claims that {} is equivalent to {:s}, which now is
only conditionally true.

I would also argue that having different behavior for {} and {:s}, which
are semantically the same in the client's eye, forces the client code to
understand more about the object they are stringifying than should be
necessary.  If one works, so should the other by all descriptions of the
format spec.  If the format spec is *just* ':s', the library should call
the target's __str__ if __format__ is not defined.  The library seems
willing to do this for the empty format string, but not when the client
code specifically asks for a string....

On Sat, Aug 18, 2018 at 10:12 AM Eric V. Smith <report@bugs.python.org>
wrote:

>
> Eric V. Smith <eric@trueblade.com> added the comment:
>
> I agree this is the desired behavior, and not a bug.
>
> Because you are not specifying a __format__ in your class,
> object.__format__ is being called. By design, it does not understand any
> formatting specifiers, instead reserving them for your class to implement.
> "!s" is the correct way to convert your type to a string. Either that, or
> add a __format__ that understands "s".
>
> Note that not all types understand "s", for example, datetime.
>
> ----------
> assignee:  -> eric.smith
> nosy: +eric.smith
> stage:  -> resolved
> status: pending -> closed
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <https://bugs.python.org/issue34425>
> _______________________________________
>
msg323887 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-08-22 14:28
About translating ":s" to "":

> The library seems
willing to do this for the empty format string, but not when the client
code specifically asks for a string....

You're not asking for a string when you specify ":s". You're asking the object to interpret "s" however it wants. For example, if the object is a datetime, you're asking for the output to be "s":

>>> f'{datetime.datetime.now():s}'
's'

versus:

>>> f'{datetime.datetime.now()}'
'2018-08-22 10:27:25.188891'

It's precisely because we want to let the object interpret the string that Python no longer guesses as to what you might mean.

For example, say you have a MyDate object, that doesn't support __format__, and you want Python to decide that format(MyDate(), 's') means is the same as format(MyDate(), ''). But later you decide that you want the format strings to call strftime (like datetime does). You couldn't do that without breaking existing usage of your library.

This actually happened with complex when I added complex.__format__.
msg323891 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-08-22 15:44
Forgot to add: I haven't looked at the docs yet, but I agree they should be clear on this issue.

The docs should say: for types that implement the documented mini-language, "s" is the same as "". It's just that not all types implement the mini-language (like datetime, and probably many non-standard, user-defined types).

If they don't say that, can you open a separate documentation issue? Thanks.

Or, maybe the problem is that the docs make it seem like all types do (or should?) implement the mini-language? That's definitely not true, and they shouldn't say that.
History
Date User Action Args
2018-08-22 15:44:49eric.smithsetmessages: + msg323891
2018-08-22 14:28:21eric.smithsetmessages: + msg323887
2018-08-20 16:26:18Jason Spencersetmessages: + msg323798
2018-08-18 17:12:08eric.smithsetstatus: pending -> closed

nosy: + eric.smith
messages: + msg323719

assignee: eric.smith
stage: resolved
2018-08-18 04:59:44martin.pantersetstatus: open -> pending

nosy: + martin.panter
messages: + msg323689

superseder: object.__format__ should reject format strings
resolution: not a bug
2018-08-18 00:18:56Jason Spencercreate