How to save a presentation to a file-like object in Python 3

陌路散爱 提交于 2019-12-10 17:36:21

问题


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?


回答1:


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.




回答2:


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 :)




回答3:


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) 


来源:https://stackoverflow.com/questions/46979457/how-to-save-a-presentation-to-a-file-like-object-in-python-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!