我编写了一个脚本来使用 python/tkinter 和 speedtest 库 (speedtest/speedtest-cli) 执行许多宽带速度测试。当作为普通 python 脚本运行时,该程序按预期工作。我可以使用 cx_freeze 创建一个 exe 文件,它会正常创建所有内容。当我运行 exe 文件时,我得到以下回溯...
Traceback (most recent call last):
File
"c:\@python\@w4itdev\lib\site-packages\speedtest.py",
line 156, in <module>
import_builtin___
ModuleNotFoundError: No module named '__builtin__
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File
"C:\@python\@w4itdev\Lib\site-packages\cx_Freeze\initscript s_startup__.py", line 141, in run module_init.run(name + "__main__")
File
"C:\@python\@w4itdev\Lib\site-packages\cx_Freeze\initscript
s\console.py", line 25, in run
exec(code, main_globals) File "st.py", line 2, in <module>
File "c:\@python\@w4itdev\lib\site-packages\speedtest.py", line 179, in <module>
_py3_utf8_stdout= _Py3Utf8Output(sys.stdout)
File "c:\@python\@w4itdev\lib\site-packages\speedtest.py", line 166, in __init__
buf FilelO(f.fileno), 'w')
AttributeError: 'NoneType' object has no attribute 'fileno'
我已经获取了一个更简单的 python 脚本,该脚本执行类似的工作来测试我的代码是否犯了错误。这给出了相同的结果。为了简单起见,我包含了简单的脚本,而不是我原来的脚本。
from tkinter import *
from speedtest import Speedtest
def update_text():
speed_test = Speedtest()
download = speed_test.download()
upload = speed_test.upload()
download_speed = round(download / (10**6), 2)
upload_speed = round(upload / (10**6), 2)
down_label.config(text= "Download Speed - " + str(download_speed) + "Mbps")
up_label.config(text= "Upload Speed - " + str(upload_speed) + "Mbps")
root = Tk()
root.title("Internet Speed Tracker")
root.geometry('300x300')
button = Button(root, text="Get Speed", width=30, command=update_text)
button.pack()
down_label = Label(root, text="")
down_label.pack()
up_label = Label(root, text="")
up_label.pack()
root.mainloop()
虽然我不是专家,但它似乎是 tkinter/speedtest/cx_freeze 和最终 stdout 的组合。
BTW .. chatgpt 一直在兜圈子试图解决这个问题。
The problem stems from how cx_Freeze handles standard input/output streams (stdin, stdout) when creating an executable. The speedtest library, particularly the
_Py3Utf8Output
class used for ensuring UTF-8 output, attempts to access the
fileno()
method of
sys.stdout
. However, cx_Freeze might redirect or nullify these streams in the frozen executable, leading to the
AttributeError: 'NoneType' object has no attribute 'fileno'
.
Here are the common solutions to address this issue:
1. Redirect stdout in your script:
You can explicitly redirect stdout to a file before running your main code. This way, speedtest will have a valid file descriptor to work with.
```python import sys import os
if sys.stdout is None: # Check if stdout is None sys.stdout = open(os.devnull, 'w')
from tkinter import * from speedtest import Speedtest
# ... rest of your code ... ```
2. Monkey patch
sys.stdout
:
Before importing speedtest, you can monkey patch
sys.stdout
with an object that has a
fileno()
method.
```python import sys
class FakeStdOut: def fileno(self): return 0
if sys.platform.startswith("win"): sys.stdout = FakeStdOut()
from tkinter import * from speedtest import Speedtest
# ... rest of your code ... ```
3. Use
hiddenimports
in cx_Freeze setup:
Sometimes, explicitly specifying hidden imports in your cx_Freeze setup script can resolve such issues. This helps the freezer bundle necessary modules that might be missed.
```python from cx_Freeze import setup, Executable
setup( name="MySpeedTestApp", version="0.1", description="Speedtest app", options={ "build_exe": { "packages": ["tkinter", "speedtest"], "includes": ["tkinter"], "hiddenimports": ["_io"], # Add other potentially missing modules if needed } }, executables=[Executable("your_script.py")] ) ```
Explanation:
- Redirecting stdout ensures that the output stream is pointed to a valid file, preventing the error.
-
Monkey patching
replaces the problematic
sys.stdout
with a custom object that fulfills thefileno()
requirement. -
Using
hiddenimports
in the cx_Freeze setup script forces the inclusion of the specified modules, which might be indirectly required by the used libraries.
Try these solutions and see if any of them resolve the issue in your cx_Freeze executable. If the problem persists, providing the complete cx_Freeze setup script and relevant code snippets will help in providing more specific guidance.
标签:python,tkinter,stdout,cx-freeze From: 78802814