Python:打印文件以在文件更改时流式传输

时间:2014-02-21 18:10:15

标签: python stdout maya

我正在通过另一个应用程序(Autodesk Maya)在子进程中运行一大组单元测试。 Maya运行一个特殊的Python解释器,它有自己的库,不能在应用程序之外使用,因此需要在应用程序内进行测试。我希望父进程在发生测试时打印测试结果。虽然子进程非常'嘈杂',所以我不想简单地将子进程的stdout重定向到父进程的stdout。相反,我希望测试运行器以某种方式直接流式传输到父进程的stdout

我目前在子进程中使用TextTestRunner,并将stdout设置为打开的文件。父进程知道此文件存在的位置,并在子进程完成后将tile的内容写入stdout。由于测试可能需要很长时间才能运行,我宁愿父进程能够以某种方式“流式传输”该文件的内容,因为它是由子进程创建的。但我不知道如何做到这一点,或者是否有更好的方法。

以下是目前如何设置的示例。

module_path = 'my.test.module'
suite_callable = 'suite'
stream_fpath = '/tmp/the_test_results.txt'
script_fpath = '/tmp/the_test_script.py'
script = '''
import sys
if sys.version_info[0] <= 2 and sys.version_info[1] <= 6:
    import unittest2 as unittest
else:
    import unittest

import {module_path}
suite = {module_path}.{suite_callable}()
with open("{stream_path}", "w") as output:
    runner = unittest.TextTestRunner(stream=output)
    runner.run(suite)
    output.close()

'''.format(**locals())

with open(script_fpath, 'w') as f:
    f.write(script)
subprocess.call(['maya', '-command', '\'python("execfile(\\"{script_fpath}\\")")\''.format(**locals())]
with open(stream_fpath, 'r') as f:
    print f.read()

感谢您的任何信息!

2 个答案:

答案 0 :(得分:0)

(已编辑 - 建议使用stderr或解析)

备选方案1:拦截输出而不是将其转到文件中。

script写信给sys.stderr而不是open() stream_fpath

runner = unittest.TextTestRunner(stream=sys.stderr)

subprocess.call替换为running = subprocess.Popen(<existing parameters>, stderr=PIPE)。然后阅读running.stderr直到EOF或直到running.poll()返回None以外的其他人。您可以使用数据执行所需操作。例如,您可以将其打印到屏幕上,然后将其打印到stream_fpath

这假设噪声输出来自maya,它仍然会转储到stdout

备选方案2:解析stdout=PIPE的嘈杂输出。如果您可以通过向每行添加一些标记来区分测试运行器的输出,则可以搜索该标记并仅打印匹配的行。

Popen documentation (Python 2)

答案 1 :(得分:0)

不是写入文件,而是应该使file-like object替换stderr。对象的write方法可以对每个输入执行某些操作;如果你还想要结果,除了记录到文件之外,你可以把它喷到听TCP的东西上,或者把东西打印到TK窗口,或其他任何东西。

实现流替换非常简单,在这种情况下,您可能只需要实现write,writelines,open和close(除非你的testrunner也使用flush)。

class FakeStdErr(object):
     def __init__(self)
         self.lines = []

     def write(self, text):
         self.lines.append(text)

    def writelines(self, *args):
         for item in args: self.lines.append(item)

    def open(self):
        self.lines = []

    def close (self):
        pass

在您的用例中,您可能希望使用silencer class(这是同一技巧的变体)来替换默认的stdout(以关闭您的聊天过程)并将测试运行器流引导到此人;完成所有测试后,您可以将内容作为文件转储到磁盘,或者通过恢复默认标准输出将其打印到屏幕上(如果您不熟悉,链接会显示如何执行此操作)。