Skip to content

:s formatting broken for objects without __format__ #78606

Closed

Description

@JasonSpencer
BPO 34425
Nosy @ericvsmith, @vadmium
Superseder
  • bpo-7994: object.format should reject format strings
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/ericvsmith'
    closed_at = <Date 2018-08-18.17:12:08.313>
    created_at = <Date 2018-08-18.00:18:55.985>
    labels = ['interpreter-core', 'type-bug', 'invalid']
    title = ':s formatting broken for objects without __format__'
    updated_at = <Date 2018-08-22.15:44:49.027>
    user = 'https://bugs.python.org/JasonSpencer'

    bugs.python.org fields:

    activity = <Date 2018-08-22.15:44:49.027>
    actor = 'eric.smith'
    assignee = 'eric.smith'
    closed = True
    closed_date = <Date 2018-08-18.17:12:08.313>
    closer = 'eric.smith'
    components = ['Interpreter Core']
    creation = <Date 2018-08-18.00:18:55.985>
    creator = 'Jason Spencer'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 34425
    keywords = []
    message_count = 6.0
    messages = ['323688', '323689', '323719', '323798', '323887', '323891']
    nosy_count = 3.0
    nosy_names = ['eric.smith', 'martin.panter', 'Jason Spencer']
    pr_nums = []
    priority = 'normal'
    resolution = 'not a bug'
    stage = 'resolved'
    status = 'closed'
    superseder = '7994'
    type = 'behavior'
    url = 'https://bugs.python.org/issue34425'
    versions = ['Python 3.5', 'Python 3.6']

    Activity

    1. JasonSpencer commented on Aug 18, 2018

      JasonSpencermannequin
      MannequinAuthor

      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'
      >>>
    2. added
      interpreter-core(Objects, Python, Grammar, and Parser dirs)
      type-bugAn unexpected behavior, bug, or error
      on Aug 18, 2018
    3. ericvsmith commented on Aug 18, 2018

      @ericvsmith
      Member

      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.

    4. self-assigned this
      on Aug 18, 2018
    5. JasonSpencer commented on Aug 20, 2018

      JasonSpencermannequin
      MannequinAuthor

      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 <[email protected]>
      wrote:

      Eric V. Smith <[email protected]> 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 <[email protected]>
      <https://bugs.python.org/issue34425\>


    6. ericvsmith commented on Aug 22, 2018

      @ericvsmith
      Member

      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__.

    7. ericvsmith commented on Aug 22, 2018

      @ericvsmith
      Member

      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.

    8. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions