从烧瓶应用程序调用 python 函数
Posted
技术标签:
【中文标题】从烧瓶应用程序调用 python 函数【英文标题】:calling a python function from flask app 【发布时间】:2018-01-22 19:10:43 【问题描述】:我正在开发一个在 python 中运行的应用程序(总是 - 它是热泵系统的控制器),我使用烧瓶提供用户界面来控制应用程序。
flask 应用具有不同的控制项,例如用于打开或关闭系统的按钮。
我正在尝试从 python 模块执行特定函数以响应按钮上的“单击”(最终目标是更改 mmap 资源中的值,该值将在另一个模块中读取以更改系统)。
在烧瓶应用程序中,我有类似的东西:
@app.route('/cntr_hpauto',methods=['GET','POST'])
@basic_auth.required
def cntr_hpauto():
manage_globals.set_from_web()
return render_template('control.html',cur_hp_mode="auto")
但是,这会产生“内部服务器错误”
完整的烧瓶应用程序是(manage_globals 是我要导入的 *.py 文件,其中包含我要调用的函数):
from flask import Flask, request, render_template
from flask_basicauth import BasicAuth
import sys
import os
import mmap
import manage_globals
app = Flask(__name__)
app.config['BASIC_AUTH_USERNAME'] = '***'
app.config['BASIC_AUTH_PASSWORD'] = '***'
basic_auth = BasicAuth(app)
@app.route('/')
def splash():
return render_template('splash.html')
@app.route('/dashboard', methods=['GET','POST'])
@basic_auth.required
def dashboard():
return render_template('dashboard.html')
@app.route('/control',methods=['GET','POST'])
@basic_auth.required
def control():
return render_template('control.html',cur_hp_mode="none")
@app.route('/cntr_hpauto',methods=['GET','POST'])
@basic_auth.required
def cntr_hpauto():
manage_globals.set_from_web()
return render_template('control.html',cur_hp_mode="auto")
@app.route('/cntr_hpon',methods=['GET','POST'])
@basic_auth.required
def cntr_hpon():
return render_template('control.html',cur_hp_mode="on")
@app.route('/cntr_hpoff',methods=['GET','POST'])
@basic_auth.required
def cntr_hpoff():
return render_template('control.html',cur_hp_mode="off")
if __name__ == '__main__':
app.run(ssl_context=('/home/groenhol/certs/groenhol.pem', '/home/groenhol/certs/groenhol.key'))
并且模块(例如,只将映射文件写入日志文件)是:
# 14/08/2017 henk witte / groenholland
# part of geotech project, ann controller dual source heat pump
# this module maintains the global database with mmap
import mmap
""" the mmap file is position dependent!
use readlines and split
line 1: heatpump auto/on/off
line 2: userpump off
line 3: srcselect air
"""
def init_conf_file():
dummy="a"
def set_from_web():
with open("geotech.conf", "r+b") as f:
mm = mmap.mmap(f.fileno(), 0)
for line in iter(mm.readline, b''):
with open("globals.log","ab") as f2:
f2.write(line)
f2.close()
mm.close()
if __name__ == '__main__':
init_conf_file()
flask 应用程序在没有函数调用的情况下运行良好,我自己导入的模块也运行良好。
非常感谢任何帮助!
亨克
按照 Kevin Pasquarella 的建议,我添加了 app.debug = true。但是,当 apache 已经在主启动页面中加载时发生错误(apache 服务器错误),这没有帮助。但我随后查看了 apache 错误日志:
[Tue Aug 15 21:33:14.638580 2017] [mpm_event:notice] [pid 959:tid 3067240448] AH00489: Apache/2.4.18 (Ubuntu) OpenSSL/1.0.2g mod_wsgi/4.5.17 Python/3.4 configured -- resuming normal operations
[Tue Aug 15 21:33:14.639152 2017] [core:notice] [pid 959:tid 3067240448] AH00094: Command line: '/usr/sbin/apache2'
[Tue Aug 15 21:33:19.825211 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] mod_wsgi (pid=2461): Target WSGI script '/home/groenhol/py_control/ui/webapp/main.wsgi' cannot be loaded as Python module.
[Tue Aug 15 21:33:19.826502 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] mod_wsgi (pid=2461): Exception occurred processing WSGI script '/home/groenhol/py_control/ui/webapp/main.wsgi'.
[Tue Aug 15 21:33:19.967421 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] Traceback (most recent call last):
[Tue Aug 15 21:33:19.970377 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] File "/home/groenhol/py_control/ui/webapp/main.wsgi", line 4, in <module>
[Tue Aug 15 21:33:19.970581 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] from main import app as application
[Tue Aug 15 21:33:19.971031 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] File "/home/groenhol/py_control/ui/webapp/main.py", line 41
然后我搜索了 mod_wsgi cannot be loaded as python module
答案表明我使用的 python 版本 (3.4) 和 wsgi 版本之间存在差异。
所以我检查了 /etc/apache2/mods-enabled/mod-wsgi.load 中的 wsgi 版本:
LoadModule wsgi_module "/home/groenhol/miniconda3/lib/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so" WSGIPythonHome "/home/groenhol/miniconda3"
所以好像用python 3.4版本。
为了确保我使用搜索过程中发现的 ldd:
groenhol@arm:~/mod_wsgi-4.5.15$ ldd LoadModule wsgi_module "/home/groenhol/miniconda3/lib/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so"
LoadModule:
ldd: ./LoadModule: No such file or directory
wsgi_module:
ldd: ./wsgi_module: No such file or directory
/home/groenhol/miniconda3/lib/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so:
linux-vdso.so.1 => (0xbee90000)
libpython3.4m.so.1.0 => /home/groenhol/miniconda3/lib/libpython3.4m.so.1.0 (0xb6d40000)
libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6d0f000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6c23000)
/lib/ld-linux-armhf.so.3 (0x7f64d000)
libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb6c10000)
libutil.so.1 => /lib/arm-linux-gnueabihf/libutil.so.1 (0xb6bfd000)
libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0xb6b85000)
libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb6b5c000)
groenhol@arm:~/mod_wsgi-4.5.15$ WSGIPythonHome "/home/groenhol/miniconda3"
-bash: WSGIPythonHome: command not found
据我所知 (http://modwsgi.readthedocs.io/en/develop/user-guides/checking-your-installation.html#python-shared-library) 这似乎没问题?
好的,那么下一步?
【问题讨论】:
在您的应用文件中的if __name__ == '__main__': app.run(...)
下,添加app.debug = True
,以便您可以追溯错误及其来源,并将其添加到帖子中
从 traceback 看来这里有一个错误:from main import app as application
也许,但只有当我尝试从我导入的 *.py 模块调用函数时才会发生错误。似乎只有烧瓶函数在这种情况下有效。当我执行它时,模块本身运行良好,只是无法从烧瓶 main.py 中调用它,并在 apache 加载页面/应用程序时引发 wsgi 错误。
到目前为止,我发现可能的问题是编译 wsgi 所针对的 python 版本不同,以及关于据称需要在虚拟 python 环境中运行的评论。
嗯。当您在本地运行应用程序时会发生什么?是的,运行虚拟环境将有助于解决依赖性和版本问题
【参考方案1】:
结果证明解决方案非常简单:mod_wsgi 不喜欢你用空格和制表符来标识。我将所有 idents 更改为选项卡,然后代码运行!
我通过将代码更改为非常简单的代码来发现这一点,只需返回一个字符串并将其打印在烧瓶模板创建的网页上。然后我可以在 apache 日志中看到 wsgi 错误。在完整的代码中出现了其他错误,因此很难找出究竟是什么导致了错误。
我还处理了 Graham Dumpleton 的评论(即 apache 无法写入目录),我创建了一个共享目录 (/home/py_shared),并将其添加到 www-data 组(python 用户和apache 是该组的成员)。然后我将文件夹的组设置为 www-data 并使用 chmod g+w py_shared 和 chmod g+s py_shared 设置正确的权限。
这个话题在几个页面上讨论过,例如:
https://unix.stackexchange.com/questions/154776/create-files-that-both-www-data-and-myuser-can-edit
感谢您的所有建议!
【讨论】:
制表符和空格的混合是 Python 的一个普遍问题,并不特定于 mod_wsgi。如果您已覆盖编辑器设置以使选项卡宽度显示为 8 个字符以外的任何内容,则会出现问题。最好设置一个编辑器自动用空格替换选项卡。 感谢 Graham,对编程并不陌生(主要是 c/fortran),但这是我的第一个 python 项目,还有很多“功能”有待发现。【参考方案2】:代码:
def set_from_web():
with open("geotech.conf", "r+b") as f:
mm = mmap.mmap(f.fileno(), 0)
for line in iter(mm.readline, b''):
with open("globals.log","ab") as f2:
f2.write(line)
f2.close()
mm.close()
这将是一个问题,因为您使用的是文件的相对路径名。
进程的当前工作目录将不是您的代码所在的位置,也对 Apache 用户不可写。您需要使用绝对路径并确保 Apache 用户对文件具有写入权限。
见:
http://modwsgi.readthedocs.io/en/develop/user-guides/application-issues.html#application-working-directory http://modwsgi.readthedocs.io/en/develop/user-guides/application-issues.html#access-rights-of-apache-user【讨论】:
谢谢你,我同意,还没有考虑过。我需要确保这得到纠正!但是,为了检查这是否是我的问题的原因,我将函数更改为 simpe dummy = "b" 语句。当在 main.py 中给出引用(而不是调用!)这个函数时,服务器会在加载时抛出错误。 问题是你没有从错误日志中包含完整的 Python 回溯,以及异常名称和描述。除非你能提供,否则只能猜测错误的来源。以上是关于从烧瓶应用程序调用 python 函数的主要内容,如果未能解决你的问题,请参考以下文章
无法从另一个 docker 容器中的烧瓶应用程序对驻留在 docker 容器中的 django 应用程序进行“获取”调用 [重复]