使用Django生成LaTeX PDF时出现FileNotFoundError

时间:2017-02-28 01:40:18

标签: python django python-3.x latex pdflatex

根据给定here的示例,我正在尝试使用Django应用程序从用LaTeX编写的模板生成PDF。请注意,我还没有进入使用数据库中的值填充LaTeX模板文件的阶段。它目前有“硬编码”内容,我只是想让PDF生成工作先发挥作用。

views.py

from django.shortcuts import render
from django.http import HttpResponse
from django.template import Context
from django.template.loader import get_template
from subprocess import Popen, PIPE
import tempfile

def pdf(request):
    context = Context({})
    template = get_template('cv.tex')
    rendered_tpl = template.render(context).encode('utf-8')  
    with tempfile.TemporaryDirectory() as tempdir:  
        # Create subprocess, supress output with PIPE and
        # run latex twice to generate the TOC properly.
        # Finally read the generated pdf.
        for i in range(2):
            process = Popen(
                ['pdflatex', '-output-directory', tempdir],
                stdin=PIPE,
                stdout=PIPE,
            )
            process.communicate(rendered_tpl)
        with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f:
            pdf = f.read()
    r = HttpResponse(content_type='application/pdf')  
    r.write(pdf)
    return r

但是当我转到我指向视图的URL时,我收到以下错误。

Internal Server Error: /cv.pdf
Traceback (most recent call last):
  File "C:\Python34\lib\site-packages\django\core\handlers\base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Python34\lib\site-packages\django\core\handlers\base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\LThorburn\Documents\Dropbox\Code\lt.co\cv\views.py", line 45, in pdf
    with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\LTHORB~1\\AppData\\Local\\Temp\\tmpik2iw24w\\texput.
pdf'

我对处理临时文件不是很熟悉。我需要做什么?

修改

为了回应@ stovfl的建议,我将with tempfile.TemporaryDirectory() as tempdir:替换为with tempfile.TemporaryDirectory(dir='.') as tempdir:。这导致了以下新错误:

C:\Users\LThorburn\Documents\Dropbox\Code\lt.co\cv\views.py:33: RemovedInDjango110Warning: render() must be called with
a dict, not a Context.
  rendered_tpl = template.render(context).encode('utf-8')

pdflatex: Unknown archive file size.
pdflatex: Data: resume
pdflatex: Unknown archive file size.
pdflatex: Data: resume
[FAIL] File .\tmppml24lmd\texput.pdf not found
Internal Server Error: /cv.pdf
Traceback (most recent call last):
  File "C:\Users\LThorburn\Documents\Dropbox\Code\lt.co\cv\views.py", line 51, in pdf
    with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f:
FileNotFoundError: [Errno 2] No such file or directory: '.\\tmppml24lmd\\texput.pdf'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python34\lib\site-packages\django\core\handlers\base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Python34\lib\site-packages\django\core\handlers\base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\LThorburn\Documents\Dropbox\Code\lt.co\cv\views.py", line 52, in pdf
    pdf = f.read()
  File "C:\Python34\lib\tempfile.py", line 685, in __exit__
    self.cleanup()
  File "C:\Python34\lib\tempfile.py", line 689, in cleanup
    _shutil.rmtree(self.name)
  File "C:\Python34\lib\shutil.py", line 478, in rmtree
    return _rmtree_unsafe(path, onerror)
  File "C:\Python34\lib\shutil.py", line 377, in _rmtree_unsafe
    onerror(os.rmdir, path, sys.exc_info())
  File "C:\Python34\lib\shutil.py", line 375, in _rmtree_unsafe
    os.rmdir(path)
OSError: [WinError 145] The directory is not empty: '.\\tmppml24lmd'
[08/Mar/2017 22:15:50] "GET /cv.pdf HTTP/1.1" 500 96729

2 个答案:

答案 0 :(得分:2)

错误涉及.log文件时,

初始答案,问题已更改

我不认为问题是由于' Tempfile'因为您的错误处理的是.log文件而不是像您的代码所示的随机创建的临时目录。 当我运行以下代码时:

with tempfile.TemporaryDirectory() as tempdir:
    print(os.path.join(tempdir, 'test.txt'))
    with open(os.path.join(tempdir, 'test.txt'),"w") as tmpfile:
        tmpfile.write("test.txt")

我得到以下输出: /var/folders/xj/zz73z72j0bb80kt2x6z8sfq5p7zwwg/T/tmpfhk0qwjf/test.txt

请注意,目录是随机的,而不是文件。

您似乎在访问随机生成的日志文件时遇到问题。

此外,您可能需要考虑对代码进行一些改进:

  1. 您没有为pdflatex命令失败做好准备。您假设始终生成输出文件。
  2. 您正在http处理程序中运行子进程,这通常不是一个好主意。一个主要原因是命令可能需要太长时间,客户端将超时。考虑使用像“芹菜”这样的工具。
  3. 更详细的追溯将有助于进一步追踪错误。

    更新#1

    当错误发生时,您可以尝试打印pdflatex命令的STDOUT和STDERR:

     process.communicate(rendered_tpl)
     with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f:
            pdf = f.read()
    

    使用:

    out,err = process.communicate(rendered_tpl)
    try:
        fn = os.path.join(tempdir, 'texput.pdf')
        f = open(fn)
        pdf = f.read()
        f.close()
    except FileNotFoundError:
        raise FileNotFoundError("Could not find {}.\nSTDOUT from pdflatex:{}.\nSTDERR from pdflatex:{}\n",format(fn,out,err))
    

    更新#2

    好了,现在很清楚,该命令没有生成您正在查找的文件并且给您错误LaTeX Error: File 'res.cls' not found. ... there is probably something wrong with the class file.

    您似乎需要下载res类文件才能使应用程序正常运行。您可以找到更多信息here

答案 1 :(得分:1)

  

第三次跟进:

意外结果:

  1. 在本地更改后,请更新您问题中的代码。 所以我们可以比较Output,Traceback!

  2. 请在exit(1)块中添加except,这样我们就不会对folloup错误感到不安: except os.error: print('[FAIL] File %s not found\nEXIT(1)' % path2pdf) exit(1)

  3. 请在测试时将循环次数设置为1

    for i in range(1):
    
  4. 新的错误! 您是否已双重检查插入dir='.'是唯一的更改?

  5.   

    C:\用户\ LThorburn \文件\收存箱\代码\ lt.co \ CV \ views.py:33:       RemovedInDjango110       警告:必须使用dict调用render(),而不是上下文。
          rendered_tpl = template.render(context).encode('utf-8')

    您指出的示例使用:
        context = Context({ 'content': entry.content, })
    你用的是     context = Context({})
    不得不深入研究,但由于此警告之前没有显示, 我想你已经改变了其他任何事情。

    1. 这可能是Django Warning
    2. 的后续错误
        

      pdflatex:未知的存档文件大小。       pdflatex:数据:简历

      1. process.communicate(rendered_tpl)的输出 您是否曾从命令控制台尝试过pdflatex? 是什么赋予了: C:pdflatex -output-directory - < cv.tex
      2.   

        第二次跟进:

        使用指向pdf文件的新Traceback更新问题后, 我们必须验证pdflatex无法创建pdf文件的原因。

        首先,我们检查Process是否具有写权限。

        更改你的身份     with tempfile.TemporaryDirectory() as tempdir:

            with tempfile.TemporaryDirectory(dir='.') as tempdir:

        这会将tempdir从OS位置移动到您的脚本正在运行的当前目录。 请评论,因为它的行为相同。