【问题标题】:How do I change the line endings used by PExpect output如何更改 PExpect 输出使用的行尾
【发布时间】:2019-11-12 23:35:16
【问题描述】:

pexpect.run() 返回的输出在每一行的末尾包含 \r\n。使用 print(returnVal.decode()) 打印到终端会为返回的每一行正确打印一行。当我检查输出时,我看到字节字符串包含 \r\n。当我将其记录到文件中时,我会双重返回到日志文件。我在使用 Python 3.7 的 Mac 上。有没有办法在编写输出时设置首选的新行?我正在使用 pythons 日志记录类并使用 info() 方法来编写字符串。输出如下所示:

total 80
-rw-r--r--   1 xxxx  admin  1048 Nov 12 00:41 Constants.py

-rw-r--r--   1 xxxx  admin  5830 Nov 12 13:33 file1.py

-rw-r--r--   1 xxxx  admin  2255 Nov 12 00:51 file2.py

什么时候应该是这样的:

total 80
-rw-r--r--   1 xxxx  admin  1048 Nov 12 00:41 Constants.py
-rw-r--r--   1 xxxx  admin  5830 Nov 12 13:33 file1.py
-rw-r--r--   1 xxxx  admin  2255 Nov 12 00:51 file2.py

这是我原来的 Logger 类的简化版本:

class Logger():
    def __init__( self, path ):
        msgFormat   = '%(asctime)s.%(msecs)d\t%(message)s'
        dateFormat  = '%m/%d/%Y %H:%M:%S'
        logging.basicConfig( format=msgFormat, datefmt=dateFormat, filename=path, level=logging.INFO )

    def Log ( self, theStr ):
        logging.info( str( theStr ))

从 Pexpect 返回的字符串类似于:

Line1\r\nLine2

【问题讨论】:

  • 快速的解决方案是在记录之前将\r\n 替换为单个\n。日志模块似乎已经使用\n 换行,所以这不是问题。
  • @Asad 我看不到日志记录模块有办法指定行尾。到目前为止,我读到的是 python 3 将使用平台默认行结尾。因为我在使用 \r\n 的 unix (Mac) 上。我想另一种方法是让 pexpect 设置行尾,但我也没有办法做到这一点。我不想做一个黑客并成为中间人。记录器最终控制行格式,因此在那里完成工作会很好。
  • 您运行的是哪个版本的 Mac?我相信 Mac OS X 上的默认行现在是 \n。你可以做一个简单的returnVal.decode().replace("\r\n", "\n") 看看它是否能解决问题。
  • 在 10.15 上使用 Python 3.7。我会做那个快速测试。
  • @Asan Yep 修复了它,但现在我正在逐行影响文件的文件格式。我宁愿我们简单地设置记录器的行为并忘记它。 :)

标签: python-3.x pexpect


【解决方案1】:

根据您记录输出的方式,建议在发送到记录器之前格式化换行符。但是,如果您必须为 FileHandler 覆盖日志记录模块的换行参数,并且作为实验,您可以通过猴子修补其_open 方法来实现,因为默认情况下该功能不可用。

我使用 Python 3.8 版本的源代码来获取 _open 函数的定义。

import logging

def custom_open(self):
    """
    Monkey patched _open function of class logging.FileHandler (Python 3.8)

    """
    return open(self.baseFilename, self.mode, encoding=self.encoding, newline='')

logging.FileHandler._open = custom_open

if __name__ == "__main__":

    pexpect_return = "Output\nTest"
    my_log = logging.getLogger("test_logger")
    my_log.setLevel(logging.INFO)
    my_log.addHandler(logging.FileHandler("test.log"))
    my_log.info(pexpect_return)

工作原理

Python 的日志记录模块有一个类FileHandler,它使用方法_open 创建一个文件处理程序对象来写入和附加到磁盘上的日志文件。从 3.8 版开始,它的默认实现没有 newline 参数,因此它使用默认换行符。

Monkey patching 是在程序运行时替换或更新其中一个导入的类中的方法/函数。这行logging.FileHandler._open = custom_open 告诉python 用我的custom_open 方法替换FileHandler 类的_open 方法。然后稍后当我使用my_log.addHandler(logging.FileHandler("test.log")) 时,新的custom_open 方法用于使用换行参数打开文件。

您可以通过在文件名中添加后缀来进一步确认使用新方法打开文件,如下所示:

return open(self.baseFilename+"__Monkey_Patched", self.mode, encoding=self.encoding, newline='')

如果您现在运行该演示代码,文件名将是“test.log__Monkey_Patched”。

但是,此代码不会替换您作为要记录的字符串的一部分传递给记录器的任何换行符。你需要事先处理。

【讨论】:

  • 我没有打开文件。我调用 logging.basicConfig(format=msgFormat, datefmt=dateFormat, filename=path, level=logging.INFO)。看来我应该尝试在通话中添加 newline = '\n' 。然后我调用 logging.info() 来记录消息。
  • 不...那当然行不通。我看到你只是替换整个机制来获得功能。 IOW:您打开文件而不是让记录器类打开它。我将不得不制定一些细节,但你的方法可能会奏效。我复制了这个例子,但会寻找一种更直接的方法来要求记录器类做同样的事情。
  • 您的示例不起作用。我想它最初来自一个类,但诸如 self 和 self.baseFilename 之类的项目不存在。如果你会修复它,我更喜欢类版本。
  • 在发布之前,我已经测试了该演示代码(Python 3.4)。我现在添加了一个解释,以便您了解它应该如何工作,以及为什么它可能不适合您。
猜你喜欢
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 2023-01-03
  • 1970-01-01
  • 1970-01-01
  • 2022-12-22
  • 1970-01-01
  • 2016-09-07
相关资源
最近更新 更多