Python – calling a python function from flask app

flaskmod-wsgipython

I am developing an app that runs (always – it is a controller for a heat pump system) in python and I use flask to provide a user interface to controll the app.

The flask app has different control items, for instance buttons to turn the system on or off.

I am trying to execute a specific function from a python module in response to a "click" on a button (the final goal is to change a value in an mmap resource that will be read in another module to change the state of the system).

In the flask app I have something like:

    @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")

However, this generates an "internal server error'

The complete flask app is (manage_globals is the *.py file I want to import and that contains the function I want to call):

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'))

And the module (example, only writing the map file to a logfile) is:

# 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()

The flask app runs fine without the function call, the module I import by itself runs fine as well.

Any help much appreciated!

Henk

As suggested by Kevin Pasquarella I added app.debug = true. However, as the error occurs when apache is loadin the main splash page already (apache server error) this did not help. But I then looked at the apache error log:

[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

I then searched for mod_wsgi cannot be loaded as python module

Answers indicate there is a difference between the python version I am using (3.4) and the wsgi version.

So I checked the wsgi version in /etc/apache2/mods-enabled/mod-wsgi.load:

LoadModule wsgi_module "/home/groenhol/miniconda3/lib/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so"
WSGIPythonHome "/home/groenhol/miniconda3"

So seems to use python 3.4 version.

To make sure I use ldd as I found during the search:

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

As far as I can tell (http://modwsgi.readthedocs.io/en/develop/user-guides/checking-your-installation.html#python-shared-library) this seems OK?

Ok, so next step?

Best Answer

The code:

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()

is going to be a problem because you are using a relative path name to files.

The current working directory of the process will not be where your code is and also will not be writable to the Apache user. You need to use absolute paths and ensure the Apache user has write permission to files.

See: