Python 3 replaced StringIO.StringIO
with io.StringIO
. I've been able to successfully save presentations using the former, but it doesn't appear to work for the latter.
from pptx import Presentation
from io import StringIO
presentation = Presentation('presentation.pptx')
output = StringIO()
presentation.save(output)
The above code produces:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\site-packages\pptx\presentation.py", line 46, in save
self.part.save(file)
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\site-packages\pptx\parts\presentation.py", line 118, in save
self.package.save(path_or_stream)
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\site-packages\pptx\opc\package.py", line 166, in save
PackageWriter.write(pkg_file, self.rels, self.parts)
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\site-packages\pptx\opc\pkgwriter.py", line 33, in write
PackageWriter._write_content_types_stream(phys_writer, parts)
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\site-packages\pptx\opc\pkgwriter.py", line 47, in _write_content_types_stream
phys_writer.write(CONTENT_TYPES_URI, content_types_blob)
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\site-packages\pptx\opc\phys_pkg.py", line 156, in write
self._zipf.writestr(pack_uri.membername, blob)
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\zipfile.py", line 1645, in writestr
with self.open(zinfo, mode='w') as dest:
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\zipfile.py", line 1349, in open
return self._open_to_write(zinfo, force_zip64=force_zip64)
File "C:\Users\mgplante\AppData\Local\Continuum\Anaconda2\envs\ppt_gen\lib\zipfile.py", line 1462, in _open_to_write
self.fp.write(zinfo.FileHeader(zip64))
TypeError: string argument expected, got 'bytes'
Is there a way to save a presentation to to a file-like object in Python 3, or am I going to have to use Python 2 for this project?
How about BytesIO()
?
from pptx import Presentation
from io import BytesIO
presentation = Presentation('presentation.pptx')
output = BytesIO()
presentation.save(output)
This removes the error at least.
Hannu's answer is quite right, and is precisely the code that is used to verify this behavior in the test suite for python-pptx
:
stream = BytesIO()
presentation.save(stream)
https://github.com/scanny/python-pptx/blob/master/features/steps/presentation.py#L105
If that code is giving you a blank presentation, then something else is going on. I would reproduce that behavior, get it stable and repeatable, then ask the question to the effect "Why am I getting a blank presentation?" in another SO question, posting with it the full minimum code that gives you that behavior.
This is the second time I've heard of something like this, which makes me suspect there's actually something half-way systematic happening under the covers to produce this behavior. But at the same time, it's extremely unlikely that you would end up with a fully working presentation, just empty of slides, as a partial failure of attempting a save to a stream.
A common situation that could lead to this is saving a newly-opened default presentation, like:
prs = Presentation()
output = BytesIO()
prs.save(output)
This of course is not something you would likely do on purpose, but easy enough to do by accident, so I thought I'd mention.
If you can help us repeat your result we'll get it figured out :)
I faced the same problem while developing CGI-like presentation. My pptx shoud be sent as a file to user. You can send pptx as a file using BytesIO, not StringIO
qs = cgi.FieldStorage()
link = qs.getfirst('link', 'default_link_for_debug')
...
...
target_stream = BytesIO()
prs.save(target_stream)
target_stream.seek(0) # important!
length = target_stream.getbuffer().nbytes
buffer = target_stream.getbuffer()
#buffer = target_stream.read() # it also works
if 'HTTP_HOST' in os.environ:
sys.stdout.buffer.write(b'Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation\r\n')
sys.stdout.buffer.write('Content-Disposition: attachment; filename="offer-{0}.pptx"\r\n'.format(link).encode('ascii'))
sys.stdout.buffer.write('Content-Length: {0}\r\n'.format(length).encode('ascii'))
sys.stdout.buffer.write(b'Pragma: no-cache\r\n')
sys.stdout.buffer.write(b'\r\n')
sys.stdout.buffer.write(buffer)
else: # for debug
with open("offer-{0}.pptx".format(link),'wb') as out:
out.write(buffer)