2014-12-05 65 views
3

我必须从python运行wkhtmltopdf与subprocess.call(...)。从命令行我可以没有问题地生成pdf,但是当它从python运行时,它会因为段错误而失败。wkhtmltopdf从python运行时的段错误

我不知道是什么导致wkhtmltopdf segfault。

我甚至尝试发送我的终端env属性,但它仍然seg段。我发送了stderr,stdin,stdout但没有任何效果。令我担心的是它从终端运行,而不是从python运行。

另外,在python中调用不同进程的进程也会导致段错误。例如,我添加了一个脚本来调用这个应用程序,用python编写的脚本也从wkhtmltopdf收到段错误。

#!/bin/env python 
import subprocess 
import sys 
import pdb 
import os 


sys.argv[0] = "/usr/local/bin/wkhtmltopdf.b" 

sys.argv.remove('--quiet') 

status = subprocess.call(sys.argv, 
    env=env, 
    stdin=sys.stdin, 
    stdout=open("/tmp/stdout.w", "w"), 
    stderr=open("/tmp/stderr.w", "w")) 

cmd = " ".join(sys.argv) 

pdb.set_trace() 

现在我正在这样做,让我有时间在外部终端中执行命令。 OpenErp正在检查PDF文件的内容。 wkhtmltopdf.b是原始二进制文件。我删除了安静的参数,因为我想看看发生了什么。

它显然出现segfaults在这一刻:

Loading pages (1/6) 
[======>              ] 10% 

,并没有别的

我wkhtmltopdf AMD64从网站静态的版本wkhtmltopdf.org

$ wkhtmltopdf -V 
wkhtmltopdf 0.12.1 (with patched qt) 

我跑的一个我的gentoo盒子上的ubuntu amd64二进制包。在gentoo上使用修补过的qt编译wkhtmltopdf并不是默认支持,这是很难/很长时间。然而,由于它是从命令行运行的,它也应该从python运行。

我从zsh的运行,但即使我的Python程序里面我会改为调用是这样的:

'/bin/sh -c "%s"' % command 

这也将段错误。

+0

Python的子进程启动一个新的shell,它可能不会继承几个shell设置和环境变量。例如,你可以在你的命令行上有一个'LD_LIBRARY_PATH'指向'wkhtmltopdf'使用的一个更新的库,当通过'subprocess'启动时这个路径是缺乏的,因此'wkhtmltopdf'会回退到一个较旧的库,导致段错误。尝试搜索一个或多个导致'wkhtmltopdf'在命令行上正常运行的shell /环境变量。 – Evert 2014-12-05 13:28:31

+0

@Evert我想到了。我用终端上的'env'的结果更新了'env'字典。我把它拿出来,因为它很大。但是env和我的终端一样。 – 2014-12-06 10:44:02

+0

只需进行仔细检查,从cmdline运行或从子进程运行时打印出您的环境。 – Evert 2014-12-06 18:25:42

回答

1

我和你的问题完全相同,但是运行的是不同的堆栈(Apache & PHP),但我不是100%确定如何启动你的python。无论如何,它崩溃在你的地方完全一样,它从命令行工作正常,所以我想这可能是值得分享的情况下,可以帮助任何人;)

我发现我的问题是一个ulimit设置不同通过Apache然后shell。具体来说,我的“虚拟内存”ulimit -v非常低。我最终做$ cmd =“ulimit -v 1073741824; {$ this-> wkhtmltopdf_path} ....”并解决了我的问题! (您可以运行ulimit -a来检查,并比较shell中相同命令的值!)

+0

我得试试这个。 – 2015-03-24 08:21:41

+1

好吧,不能说我的情况100%是正确的,因为ulimit不会对odoo产生任何影响......但我更改了控制内存使用的参数,并将ulimit设置为超过1g的ram类型来解决问题。 – 2016-04-12 08:51:51

0

尝试通过标准输入传递HTML字符串。下面是一个示例,后面跟着一个下载响应。

from subprocess import Popen, PIPE, STDOUT 
from django.core.files.temp import NamedTemporaryFile 
from django.template.loader import render_to_string 
from django.http import HttpResponse 

tmp = NamedTemporaryFile() 
html = render_to_string('your-template.html', context) 
p = Popen(['wkhtmltopdf', '-', tmp.name], stdout=PIPE, stdin=PIPE, stderr=STDOUT) 
out, err = p.communicate(input=(html + u'\n').encode('utf-8')) 
# check for errors in 'out' and 'err' -- print out, err 
with open(tmp.name, 'r') as pdf: 
    pdfcontent = pdf.read() 
response = HttpResponse(pdfcontent, content_type='application/pdf') 
response['Content-Disposition'] = 'attachment; filename=print.pdf' 
response['Content-Length'] = len(pdfcontent) 
return response 

你将不得不使用全静态URL在您的模板,以防止wkhtmltopdf从没有找到静态CSS和JS文件。