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.

Author Alexander.Kruppa
Recipients Alexander.Kruppa
Date 2012-11-27.14:38:48
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1354027130.07.0.897738205773.issue16564@psf.upfronthosting.co.za>
In-reply-to
Content
I'm trying to use the email.* functions to craft HTTP POST data for file upload. Trying something like

filedata = open("data", "rb").read()
postdata = MIMEMultipart()
fileattachment = MIMEApplication(filedata, _encoder=email.encoders.encode_noop)
postdata.attach(fileattachment)
fp = BytesIO()
g = BytesGenerator(fp)
g.flatten(postdata, unixfrom=False)

fails with 

Traceback (most recent call last):
  File "./minetest.py", line 30, in <module>
    g.flatten(postdata, unixfrom=False)
  File "/usr/lib/python3.2/email/generator.py", line 91, in flatten
    self._write(msg)
  File "/usr/lib/python3.2/email/generator.py", line 137, in _write
    self._dispatch(msg)
  File "/usr/lib/python3.2/email/generator.py", line 163, in _dispatch
    meth(msg)
  File "/usr/lib/python3.2/email/generator.py", line 224, in _handle_multipart
    g.flatten(part, unixfrom=False, linesep=self._NL)
  File "/usr/lib/python3.2/email/generator.py", line 91, in flatten
    self._write(msg)
  File "/usr/lib/python3.2/email/generator.py", line 137, in _write
    self._dispatch(msg)
  File "/usr/lib/python3.2/email/generator.py", line 163, in _dispatch
    meth(msg)
  File "/usr/lib/python3.2/email/generator.py", line 192, in _handle_text
    raise TypeError('string payload expected: %s' % type(payload))
TypeError: string payload expected: <class 'bytes'>

This is because BytesGenerator._handle_text() expects str payload in which byte values that are non-printable in ASCII have been replaced by surrogates. The example above creates a bytes payload, however, for which super(BytesGenerator,self)._handle_text(msg) = Generator._handle_text(msg) throws the exception.

Note that using any email.encoders other than encode_noop does not really fit the HTTP POST bill, as those define a Content-Transfer-Encoding which HTTP does not know.

It would seem better to me to let BytesGenerator accept a bytes payload and just copy that to the output, rather than making the application encode the bytes as a string, hopefully in a way that s.encode('ascii', 'surrogateescape') can invert.

E.g., a workaround class I use now does

class FixedBytesGenerator(BytesGenerator):
    def _handle_bytes(self, msg):  
        payload = msg.get_payload()
        if payload is None:
            return
        if isinstance(payload, bytes):
            self._fp.write(payload)   
        elif isinstance(payload, str):
            super(FixedBytesGenerator,self)._handle_text(msg)
        else:
            # Payload is neither bytes not string - this can't be right
            raise TypeError('bytes or str payload expected: %s' % type(payload))
    _writeBody = _handle_bytes
History
Date User Action Args
2012-11-27 14:38:50Alexander.Kruppasetrecipients: + Alexander.Kruppa
2012-11-27 14:38:50Alexander.Kruppasetmessageid: <1354027130.07.0.897738205773.issue16564@psf.upfronthosting.co.za>
2012-11-27 14:38:49Alexander.Kruppalinkissue16564 messages
2012-11-27 14:38:48Alexander.Kruppacreate