Skip to content

email.header.decode_header sometimes returns bytes, sometimes str #65691

Open

Description

@jimminter
mannequin
BPO 21492
Nosy @warsaw, @ezio-melotti, @bitdancer, @berkerpeksag, @louisabraham
Dependencies
  • bpo-6302: Add decode_header_as_string method to email.utils
  • 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 = None
    closed_at = None
    created_at = <Date 2014-05-13.09:08:05.923>
    labels = ['3.7', '3.8', 'expert-email', '3.9', 'type-feature', 'library', 'docs']
    title = 'email.header.decode_header sometimes returns bytes, sometimes str'
    updated_at = <Date 2019-06-07.18:44:38.667>
    user = 'https://bugs.python.org/jimminter'

    bugs.python.org fields:

    activity = <Date 2019-06-07.18:44:38.667>
    actor = 'terry.reedy'
    assignee = 'docs@python'
    closed = False
    closed_date = None
    closer = None
    components = ['Documentation', 'Library (Lib)', 'email']
    creation = <Date 2014-05-13.09:08:05.923>
    creator = 'jim_minter'
    dependencies = ['6302']
    files = []
    hgrepos = []
    issue_num = 21492
    keywords = []
    message_count = 5.0
    messages = ['218419', '218442', '218450', '218451', '344522']
    nosy_count = 7.0
    nosy_names = ['barry', 'ezio.melotti', 'r.david.murray', 'docs@python', 'berker.peksag', 'jim_minter', '[email protected]']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = 'needs patch'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue21492'
    versions = ['Python 3.7', 'Python 3.8', 'Python 3.9']

    Activity

    1. jimminter commented on May 13, 2014

      jimmintermannequin
      MannequinAuthor
      Python 3.3.2 (default, Mar  5 2014, 08:21:05) 
      [GCC 4.8.2 20131212 (Red Hat 4.8.2-7)] on linux
      Type "help", "copyright", "credits" or "license" for more information.
      >>> import email.header
      >>> email.header.decode_header("foo")
      [('foo', None)]
      >>> email.header.decode_header("foo=?windows-1252?Q?bar?=")
      [(b'foo', None), (b'bar', 'windows-1252')]

      I may well be wrong, but I believe it's erroneous that in the second example above, b'foo' is returned instead of the expected 'foo'.

    2. added
      type-bugAn unexpected behavior, bug, or error
      stdlibStandard Library Python modules in the Lib/ directory
      on May 13, 2014
    3. berkerpeksag commented on May 13, 2014

      @berkerpeksag
      Member

      >>> email.header.decode_header("foo")
      [('foo', None)]

      email.header.decode_header() implements rfc-2047 and the "foo" header doesn't match the syntax described in rfc-2047 (see "2. Syntax of encoded-words").

      See the code for more information:

      See the "6.1. Recognition of 'encoded-word's in message headers" section at http://www.rfc-base.org/txt/rfc-2047.txt

    4. bitdancer commented on May 13, 2014

      @bitdancer
      Member

      The error is actually the first case returning string rather than bytes. See bpo-6302.

    5. bitdancer commented on May 13, 2014

      @bitdancer
      Member

      Hmm. It looks like we decided that we couldn't fix the behavior for backward compatibility reasons. In 3.4 you can use the new email policies to get automatic, correct stringification of headers.

    6. ezio-melotti commented on Jun 4, 2019

      @ezio-melotti
      Member

      If we can't fix the behavior, it should at least be documented.

      Currently the docs says "This function returns a list of (decoded_string, charset) pairs containing each of the decoded parts of the header.". One could assume that this means that a Unicode string is returned, but and as far as I can tell, "decoded_string" means decoded from the format used by the header, not from bytes -- in fact the example below shows a byte string.
      bpo-24797 suggest an alternative solution, but there is no indications about it in the docs except an easy-to-miss note about the new API at the top.

      Coincidentally as I was reporting this issue I also found the recently opened bpo-37139. There are also a few other reports: bpo-24797, bpo-37139, bpo-32975, bpo-6302, bpo-4661.

      If this method is not actually deprecated, I would document the current behavior (i.e. sometimes it returns bytes, sometimes unicode -- bonus points if there's a simple rule to predict which one), explain that it exists for legacy/backward-compatibility reasons, and point to the alternatives.

      FWIW here are 3 more samples that show the inconsistency.

      >>> from email.header import decode_header
      >>> # str + None
      >>> h = '\x80SOKCrGxsbw===== <[email protected]>'; decode_header(h)
      [('\x80SOKCrGxsbw===== <[email protected]>', None)]
      >>> # bytes + '', bytes + None
      >>> h = '=??b?SOKCrGxsbw=====?= <[email protected]>'; decode_header(h)
      [(b'H\xe2\x82\xacllo', ''), (b' <[email protected]>', None)]
      >>> # bytes + 'utf8', bytes + None
      >>> h = '=?utf8?b?SOKCrGxsbw==?= <[email protected]>'; decode_header(h)
      [(b'H\xe2\x82\xacllo', 'utf8'), (b' <[email protected]>', None)]
    7. added
      type-featureA feature request or enhancement
      and removed
      type-bugAn unexpected behavior, bug, or error
      on Jun 4, 2019
    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

    No one assigned

      Labels

      3.7 (EOL)end of life3.8 (EOL)end of life3.9 (EOL)end of lifedocsDocumentation in the Doc dirstdlibStandard Library Python modules in the Lib/ directorytopic-emailtype-featureA feature request or enhancement

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions