我使用单个 API 路由构建了一个非常简单的 Flask 服务器。如果我只使用
python order_input_api.py
,它会运行得很好。但是,我正在尝试使用 PyInstaller 构建可执行文件。当我运行可执行文件时,如果我向 API 端点发送完全相同的请求,它将不起作用。
这是
order_input_api.py
文件的简化版本:
import sys
from flask import Flask, request, jsonify
from flask_cors import CORS
import subprocess
import socket
import json
import os
app = Flask(__name__)
CORS(app)
def find_free_port():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('localhost', 0))
return s.getsockname()[1]
def parse_output_data(output):
# Returns json data
@app.route('/process_orders', methods=['POST'])
def process_orders():
data = request.json
packages_input = '\n'.join(data['packages']) + '\n' + 'done'
python_executable = sys.executable
process = subprocess.Popen([python_executable, 'order_counter.py'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
stdout, stderr = process.communicate(input=packages_input)
if process.returncode == 0:
return parse_output_data(stdout)
else:
return jsonify({'success': False, 'error': stderr}), 500
os.chdir(app.root_path)
if __name__ == '__main__':
port = find_free_port()
with open("port_info.json", "w") as f:
json.dump({"port": port}, f)
print(port)
from waitress import serve
serve(app, host='127.0.0.1', port=port)
按照现在的设置方式,运行可执行文件后,如果我向“/process_orders”端点发送 POST 请求,我永远不会收到响应。但是,我尝试了几种不同的方法,但都收到了错误:
if __name__ == '__main__':
port = find_free_port()
with open("port_info.json", "w") as f:
json.dump({"port": port}, f)
print(port)
app.run(debug=True, host='127.0.0.1', port=port)
这导致了以下响应:
{
"error": " * Debugger is active!
* Debugger PIN: 454-500-849
Traceback (most recent call last):
File "order_input_api.py", line 63, in <module>
File "flask/app.py", line 615, in run
File "werkzeug/serving.py", line 1077, in run_simple
File "werkzeug/serving.py", line 917, in make_server
File "werkzeug/serving.py", line 784, in __init__
IndexError: string index out of range
[26517] Failed to execute script 'order_input_api' due to unhandled exception!",
"success": false
}
find_free_port()
更改为 5000
:
"...
Traceback (most recent call last):
File \"order_input_api.py\", line 63, in <module>
File \"flask/app.py\", line 615, in run
File \"werkzeug/serving.py\", line 1077, in run_simple
File \"werkzeug/serving.py\", line 917, in make_server
File \"werkzeug/serving.py\", line 779, in __init__
File \"socket.py\", line 544, in fromfd
OSError: [Errno 9] Bad file descriptor
[25777] Failed to execute script 'order_input_api' due to unhandled exception!
..."
.spec
文件并根据此链接添加
os.chdir(app.root_path)
'werkzeung'
添加到 hiddenimports
文件中的 .spec
每次我进行更改时我尝试运行脚本本身(
python order_input_api.py
),向端点发送POST请求,并且工作正常。然后运行可执行文件并发送相同的请求失败。
对于如何调试或问题可能是什么,我已经没有想法了。此时非常感谢任何帮助。
我确定问题出在使用
subprocess.Popen
并尝试调用 python
命令(或 sys.executable
):
python_executable = sys.executable
process = subprocess.Popen([python_executable, 'order_counter.py'],
由于这不起作用,我只是将
order_counter.py
的 main
作为函数导入并直接调用它,并使用 contextlib
的 redirect_stdout
捕获输出:
import io
from contextlib import redirect_stdout
from order_counter import main as order_counter
@app.route('/process_orders', methods=['POST'])
def process_orders():
try:
data = request.json
packages_input = '\n'.join(data['packages']) + '\n' + 'done'
input_stream = io.StringIO(packages_input)
output_stream = io.StringIO()
with redirect_stdout(output_stream):
sys.stdin = input_stream
order_counter()
sys.stdin = sys.__stdin__
return parse_output_data(output_stream.getvalue())
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500