“sys.stderr is None” 在使用 Pyinstaller –noconsole 编译脚本后如何修复?

huangapple go评论83阅读模式
英文:

How to fix "sys.stderr is None" after compiled a script with Pyinstaller --noconsole?

问题

环境

Windows 10

Python 3.10

Pyinstaller 5.9

问题:

我试图编译一个需要在控制台中运行一些命令行以从系统中获取一些值的脚本。

if __name__ == '__main__':
    faulthandler.enable()
    try:
        proc = subprocess.Popen(p_command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
                                stderr=subprocess.STDOUT, close_fds=True)
        output, errors = proc.communicate()
    except:
        pass

你可以使用上面的代码来重现这个错误。

当我使用控制台编译时,“exe”正常工作。但当我使用“--noconsole”编译时,“exe”失败,并显示以下错误消息:

Traceback (most recent call last):
  File "script.py", line 5432, in <module>
    faulthandler.enable()
RuntimeError: sys.stderr is None

经过几个小时的调查,我明白了来自代码“subprocess.Popen”的stdin和stdout参数不能与“--noconsole”编译模式一起使用。我尝试了以下解决方案:

stream = io.StringIO()
sys.stdout = stream
sys.stderr = stream

但它仍然不起作用。我验证了文档:
https://readthedocs.org/projects/pyinstaller/downloads/pdf/stable/
它明确指出:

(Windows) 在窗口/无控制台模式下,停止设置sys.stdout和sys.stderr为自定义的NullWriter对象,而是将它们保留为None。这与窗口式Python解释器(pythonw.exe)的行为相匹配,并防止与期望流要么为None,要么为完全与io.IOBase兼容的对象的代码之间的互操作性问题。 (#3503)

所以解决方案N°1似乎是正确的,不是吗?

去年我编译上一个版本时并没有遇到这个问题。我不明白为什么现在会出现这个问题。

请问有没有人对这个问题有解决方案?请帮帮忙。

英文:

ENVIRONMENT

Windows 10

Python 3.10

Pyinstaller 5.9

PROBLEM:

I am trying to compile a script that needs to run some command lines in the console in order to get some values from the system.

if __name__ == &#39;__main__&#39;:
    faulthandler.enable()
    try:
        proc = subprocess.Popen(p_command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
                                stderr=subprocess.STDOUT, close_fds=True)
        output, errors = proc.communicate()
    except:
        pass

You can use this code above to reproduce the error.

When I compile with the console, the "exe" works fine.
When I compile with "--noconsole", the "exe" failed with this error message :

Traceback (most recent call last):
  File &quot;script.py&quot;, line 5432, in &lt;module&gt;
    faulthandler.enable()
RuntimeError: sys.stderr is None

After a few hours of investigation, I've understood the stdin and stdout arguments from the code "subprocess.Popen) can't be used with "--noconsole" compilation mode.
I tried this solution :

stream = io.StringIO()
sys.stdout = stream
sys.stderr = stream

But it still doesn't work.
I verified the doc:
https://readthedocs.org/projects/pyinstaller/downloads/pdf/stable/
It clearly said :

> (Windows) In windowed/noconsole mode, stop setting sys.stdout and
> sys.stderr to custom NullWriter object, and instead leave them at
> None. This matches the behavior of windowed python interpreter
> (pythonw. exe) and prevents interoperability issues with code that
> (rightfully) expects the streams to be either None or objects that are
> fully compatible with io.IOBase. (#3503)

So the solution N°1 seems correct, doesn't it?

I didn't have this issue last year when I compiled the previous version. I don't understand why now there is this issue.

Does anyone have any solution to this issue PLEASE?

答案1

得分: 1

看起来你遇到了一个 RuntimeError 错误,因为 sys.stderr 为 None。faulthandler 模块需要一个有效的 stderr 流来报告错误。这可能发生在你的 Python 脚本在一个未正确设置或丢失标准错误流(sys.stderr)的环境中执行时。

要解决这个问题,你可以尝试以下之一:

在启用 faulthandler 之前设置一个有效的 stderr 流:

import sys
import os
import faulthandler
import subprocess

if sys.stderr is None:
    sys.stderr = open(os.devnull, 'w')

if __name__ == '__main__':
    faulthandler.enable()
    try:
        proc = subprocess.Popen(p_command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
        output, errors = proc.communicate()
    except:
        pass

或者,如果你想要查看错误输出,你可以将 sys.stderr 设置为 sys.stdout:

if sys.stderr is None:
    sys.stderr = sys.stdout
    ....
英文:

It seems you are running into a RuntimeError because sys.stderr is None. The faulthandler module needs a valid stderr stream to report errors. This can occur when your Python script is executed in an environment where the standard error stream (sys.stderr) is not properly set up or is missing.

To fix this issue, you can try one of the following:

Set up a valid stderr stream before enabling the faulthandler:

import sys
import os
import faulthandler
import subprocess

if sys.stderr is None:
    sys.stderr = open(os.devnull, &#39;w&#39;)

if __name__ == &#39;__main__&#39;:
    faulthandler.enable()
    try:
        proc = subprocess.Popen(p_command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
        output, errors = proc.communicate()
    except:
        pass

Alternatively, if you want to see the error output, you can set sys.stderr to sys.stdout:

if sys.stderr is None:
    sys.stderr = sys.stdout
    ....

huangapple
  • 本文由 发表于 2023年4月10日 20:22:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75977087.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定