gpt4 book ai didi

Python3 - redirected stderr not reset properly?(Python3-重定向的stderr没有正确重置?)

转载 作者:bug小助手 更新时间:2023-10-24 19:07:07 25 4
gpt4 key购买 nike



I have written function that could capture stdout and stderr into string when executing some other function. It seemed to work at first, but there is a problem with stderr not being reset properly.

我已经编写了一些函数,可以在执行其他函数时将stdout和stderr捕获为字符串。它一开始看起来很好用,但有一个问题是stderr没有被正确地重置。



It captures stderr first time, but second time, it tries to use closed string buffer, when I expect it to use new buffer.

它第一次捕获stderr,但第二次,它尝试使用关闭的字符串缓冲区,而我希望它使用新的缓冲区。



Here is my code:

以下是我的代码:



import io
import sys
import contextlib
from typing import Optional
import logging

def capture_output(
target: object,
args: Optional[tuple] = None,
kwargs: Optional[dict] = None) -> str:
"""Redirect stdout and stderr into string buffer and capture it.

target object is executed with optional args, kwargs and all stdout/
stderr that is captured, returned in string form.

Args:
target: object to execute, usually a function.
args: target positional arguments (default: {None})
kwargs: target keyword arguments (default: {None})
"""
if not args:
args = ()
if not kwargs:
kwargs = {}
# with _setup_capture_output() as sio:
with io.StringIO() as sio:
with contextlib.redirect_stdout(sio), contextlib.redirect_stderr(sio):
target(*args, **kwargs)
output = sio.getvalue()

print(output)


def dummy():
print('dummy test')
logging.warning('dummy test')

def dummy2():
print('dummy2 test')


capture_output(dummy) # works
capture_output(dummy) # won't work anymore.

capture_output(dummy2) # works
capture_output(dummy2) # works


Running capture_output second time (if stderr needs to be captured, as in logging.warning case), it errors out:

第二次运行CAPTURE_OUTPUT(如果需要捕获stderr,如logging.warning案例),它会出现错误:



--- Logging error ---
Traceback (most recent call last):
File "/usr/lib/python3.5/logging/__init__.py", line 982, in emit
stream.write(msg)
ValueError: I/O operation on closed file


P.S. if I try to catch only stdout (print), then it does not explode on any number of capture_output calls.

另外,如果我尝试只捕获stdout(Print),那么它不会在任何数量的Capture_Output调用上爆炸。


更多回答

Evidently the logging module caches the stderr file object at the first logging.warning call. Why or where it does that though, I have no idea. Probably deserves a bug report.

显然,日志记录模块在第一次logging.warning调用时缓存stderr文件对象。不过,我不知道它为什么会这么做,也不知道它在哪里做。可能需要一份错误报告。

For anyone wanting a solution to this, it was raised as a bug report (as per previous commenter's suggestion) here: bugs.python.org/issue36193. It was ultimately closed as "not a bug". I struggle to follow the details at this point, but the suggested solution, roughly speaking, was to explicitly handle the issue with logging with one approach being the example here: docs.python.org/3/howto/…

对于任何想要解决这个问题的人,它被作为错误报告(根据前面的评论者的建议)在这里提出:bugs.python.org/Issue36193。它最终以“不是一个漏洞”而被关闭。在这一点上,我很难理解细节,但粗略地说,建议的解决方案是显式地使用日志记录来处理问题,这里有一种方法:docs.python.org/3/Howto/…

优秀答案推荐

I found this problem still exists even if a handler is explicitly set. I wrapped all the details into an issue mentioned above.

我发现即使显式设置了处理程序,这个问题仍然存在。我把所有的细节都打包成了上面提到的一个问题。


https://github.com/python/cpython/issues/80374

Https://github.com/python/cpython/issues/80374


Update: In this case when loggers are used. It is the problem of setting handlers of the root logger in the redirected context and all other logger will refer to those handlers as they are children of the root logger.

更新:在使用记录器的情况下。这是在重定向上下文中设置根记录器的处理程序的问题,所有其他记录器都将引用这些处理程序,因为它们是根记录器的子级。


Some potential solutions are:

一些潜在的解决方案包括:



  • Set _LOGGER_1.propagate = False (the example child logger in this case)

  • Reconfigure the root logger like this


   def __exit__(self, exc_type, exc_val, exc_tb):
self.redirect_stdout.close()
self.redirect_stderr.close()
sys.stdout = self.original_stdout
sys.stderr = self.original_stderr
# restore any logging handler that lead to redirect_io_obj
all_loggers = [logging.getLogger("")] + [j for i, j in logging.Logger.manager.loggerDict.items()]
for logger in all_loggers:
if hasattr(logger, "handlers"):
for handler in logger.handlers:
if hasattr(handler, "stream"):
if handler.stream is self.redirect_stdout:
handler.stream = self.original_stdout
if handler.stream is self.redirect_stderr:
handler.stream = self.original_stderr

更多回答

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com