Skip to content

Problem with uploading binary files with Python 3 #217

@olivierbellone

Description

@olivierbellone

With Python 3, uploading a binary file will fail:

with open('/path/to/a/file.jpg', 'r') as fp:
    file_upload = stripe.FileUpload.create(
        purpose='dispute_evidence',
        file=fp
    )

fails with:

Traceback (most recent call last):
  <snip>
  File "/Users/ob/.pyenv/versions/3.5.1/lib/python3.5/site-packages/stripe/multipart_data_generator.py", line 28, in add_params
    self._write_file(value)
  File "/Users/ob/.pyenv/versions/3.5.1/lib/python3.5/site-packages/stripe/multipart_data_generator.py", line 54, in _write_file
    file_contents = f.read(self.chunk_size)
  File "/Users/ob/.pyenv/versions/3.5.1/lib/python3.5/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte

Opening the file as binary (e.g. replacing 'r' by 'rb' yields a different issue:

Traceback (most recent call last):
  <snip>
  File "/Users/ob/.pyenv/versions/3.5.1/lib/python3.5/site-packages/stripe/multipart_data_generator.py", line 28, in add_params
    self._write_file(value)
  File "/Users/ob/.pyenv/versions/3.5.1/lib/python3.5/site-packages/stripe/multipart_data_generator.py", line 57, in _write_file
    self._write(file_contents)
  File "/Users/ob/.pyenv/versions/3.5.1/lib/python3.5/site-packages/stripe/multipart_data_generator.py", line 50, in _write
    self.data.write(bytes(value, 'utf-8'))
TypeError: encoding or errors without a string argument

I think we ought to:

  1. Update the Python file upload examples to use mode='rb' rather than mode='r' (since image files are binary files and it makes no sense to apply an encoding to them).
  2. Patch this method that assumes that Python 3 will always deal with Unicode strings. Something like this should work:
def _write(self, value):
  if sys.version_info < (3, 0) or isinstance(value, bytes):
    self.data.write(value)
  else:
    self.data.write(bytes(value, 'utf-8'))

@brandur, any thoughts? Should I proceed with the above?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions