'How do you pass a generated PDF to an API as an IO stream without writing it to disk?

I am using PyPDF2 to generate a PDF, and I would like to upload this PDF to Cloudinary, which accepts images as IO objects.

The example from their docs: cloudinary.uploader.upload(open('/tmp/image1.jpg', 'rb'))

In my application, I instantiate a PdfFileWriter and add pages:

output = PyPDF2.PdfFileWriter()
output.addPage(page)

Then I can save the generated PDF locally:

outputStream = file(destination_file_name, "wb")
output.write(outputStream)
outputStream.close()

But obviously I'm trying to avoid this. Instead I'm trying to send an IO object to cloudinary:

image_StringIO_object = StringIO.StringIO()
output.write(image_StringIO_object)
cloudinary.uploader.upload(image_StringIO_object,
                           api_key=CLOUDINARY_API_KEY,
                           api_secret=CLOUDINARY_API_SECRET,
                           cloud_name=CLOUDINARY_CLOUD_NAME,
                           format="PDF")

This returns the error:

Empty file

If instead I try to pass the value of the StringIO object:

cloudinary.uploader.upload(image_StringIO_object.getvalue(),
                           ...)

I get the error:

file() argument 1 must be encoded string without null bytes, not str


Solution 1:[1]

Got the answer from Cloudinary support:

The result from getvalue() on the StringIO object needs to be base64 encoded and prepended with a tag:

out = StringIO.StringIO()
output.write(out)
cloudinary.uploader.upload("data:image/pdf;base64," + 
                           base64.b64encode(out.getvalue()))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 James Riley