在python3中将luigi.LocalTarget与PdfPages一起使用

时间:2019-12-12 20:13:07

标签: python-3.x matplotlib luigi

以下代码段对python2正常工作,但不适用于python3。该代码段旨在允许luigi工作流写入多页PDF,同时仍使用允许原子性的LocalTarget上下文管理器。

import luigi
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt

test = luigi.LocalTarget('test.pdf')
with test.open('wb') as fh, PdfPages(fh) as outf:
    plt = plt.plot([1, 2, 3], [4, 5, 6])

这在python2中有效,但是在python3中导致错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-ba62e5b716d2> in <module>
----> 1 with test.open('wb') as fh, PdfPages(fh) as outf:
      2     plt = plt.plot([1, 2, 3], [4, 5, 6])

~/miniconda3/envs/cat3.7/lib/python3.7/site-packages/matplotlib/backends/backend_pdf.py in __init__(self, filename, keep_empty, metadata)
   2386 
   2387         """
-> 2388         self._file = PdfFile(filename, metadata=metadata)
   2389         self.keep_empty = keep_empty
   2390 

~/miniconda3/envs/cat3.7/lib/python3.7/site-packages/matplotlib/backends/backend_pdf.py in __init__(self, filename, metadata)
    445         self.fh = fh
    446         self.currentstream = None  # stream object to write to, if any
--> 447         fh.write(b"%PDF-1.4\n")    # 1.4 is the first version to have alpha
    448         # Output some eight-bit chars as a comment so various utilities
    449         # recognize the file as binary by looking at the first few

TypeError: write() argument must be str, not bytes

如何在python3中保留此原子功能?

2 个答案:

答案 0 :(得分:1)

对不起,我知道这不是您要寻找的答案,但是我在Luigi存储库的LocalTarget定义中找到了这一行:

def open(self, mode='r'):
    rwmode = mode.replace('b', '').replace('t', '')
    ...

https://github.com/spotify/luigi/blob/master/luigi/local_target.py#L159

似乎他们没有做任何字节写操作(至少在当前版本中)。我一定会在Github Issues中提出这个问题。

答案 1 :(得分:1)

我不是LocalTarget的专家,所以我不知道是否有删除b标志的原因,或者这是一个错误。

解决此问题的一种方法是使用temporary_path函数包装代码:

import luigi

class BinaryFileExample(luigi.Task):
    def output(self):
        return luigi.LocalTarget("simple_binary_file.extension")

    def run(self):
        with self.output().temporary_path() as my_binary_file_path:
            with open(my_binary_file_path, 'wb') as inner_file:
                newFileBytes = [123, 3, 255, 0, 100]
                for byte in newFileBytes:
                    inner_file.write(byte.to_bytes(1, byteorder='big'))