Search code examples
pythonmod-wsgipygal

Pygal import failure in apache


I'm trying to run a simple Flask web app that displays a pygal graph. When I run it with the python development server, the application runs fine. However, when I try to run it in apache2, I get the following error:

[Thu Dec 10 19:55:22.745469 2020] [wsgi:error] [pid 17741] [client ::1:34366] mod_wsgi (pid=17741): Failed to exec Python script file '/var/www/FlaskApp/FlaskApp.wsgi'.
[Thu Dec 10 19:55:22.745521 2020] [wsgi:error] [pid 17741] [client ::1:34366] mod_wsgi (pid=17741): Exception occurred processing WSGI script '/var/www/FlaskApp/FlaskApp.wsgi'.
[Thu Dec 10 19:55:22.745553 2020] [wsgi:error] [pid 17741] [client ::1:34366] Traceback (most recent call last):
[Thu Dec 10 19:55:22.745586 2020] [wsgi:error] [pid 17741] [client ::1:34366]   File "/var/www/FlaskApp/FlaskApp.wsgi", line 8, in <module>
[Thu Dec 10 19:55:22.745650 2020] [wsgi:error] [pid 17741] [client ::1:34366]     from FlaskApp import app as application
[Thu Dec 10 19:55:22.745665 2020] [wsgi:error] [pid 17741] [client ::1:34366]   File "/var/www/FlaskApp/FlaskApp/__init__.py", line 2, in <module>
[Thu Dec 10 19:55:22.745707 2020] [wsgi:error] [pid 17741] [client ::1:34366]     import pygal
[Thu Dec 10 19:55:22.745723 2020] [wsgi:error] [pid 17741] [client ::1:34366]   File "/var/www/FlaskApp/FlaskApp/venv/lib/python3.8/site-packages/pygal/__init__.py", line 28, in <module>
[Thu Dec 10 19:55:22.745786 2020] [wsgi:error] [pid 17741] [client ::1:34366]     import pkg_resources
[Thu Dec 10 19:55:22.745838 2020] [wsgi:error] [pid 17741] [client ::1:34366]   File "/var/www/FlaskApp/FlaskApp/venv/lib/python3.8/site-packages/pkg_resources/__init__.py", line 1365
[Thu Dec 10 19:55:22.745850 2020] [wsgi:error] [pid 17741] [client ::1:34366]     raise SyntaxError(e) from e
[Thu Dec 10 19:55:22.745857 2020] [wsgi:error] [pid 17741] [client ::1:34366]                             ^
[Thu Dec 10 19:55:22.745864 2020] [wsgi:error] [pid 17741] [client ::1:34366] SyntaxError: invalid syntax

Here is the code that I'm running

# -*- coding: utf-8 -*-
import pygal
from flask import Flask, Response


app = Flask(__name__)


@app.route('/')
def index():
    """ render svg on html """
    return """
<html>
    <body>
        <h1>hello pygal</h1>
        <figure>
        <embed type="image/svg+xml" src="/graph/" />
        </figure>
    </body>
</html>'
"""


@app.route('/graph/')
def graph():
    """ render svg graph """
    bar_chart = pygal.Bar()
    bar_chart.add('Fibonacci', [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55])
    return Response(response=bar_chart.render(), content_type='image/svg+xml')


if __name__ == '__main__':
    app.run()

(Note that this code is just a sample copied from github)

Here is my apache site configuration:

<VirtualHost *:443>
    ServerName flaskapp.localhost
    ServerAdmin [email protected]
    WSGIScriptAlias / /var/www/FlaskApp/FlaskApp.wsgi
    
    <Directory /var/www/FlaskApp/FlaskApp/>
        Order allow,deny
        Allow from all
    </Directory>
    Alias /static /var/www/FlaskApp/FlaskApp/static
    <Directory /var/www/FlaskApp/FlaskApp/static/>
        Order allow,deny
        Allow from all
    </Directory>

    DocumentRoot /var/www/FlaskApp

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt
    SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key

    ErrorLog ${APACHE_LOG_DIR}/FlaskApp-error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/FlaskApp-access.log combined

    AddDefaultCharset utf-8

</VirtualHost>

Here is my wsgi file:

python_home = '/var/www/FlaskApp/FlaskApp/venv'

activate_this = python_home + '/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0,"/var/www/FlaskApp/")
sys.path.insert(0,"/var/www/FlaskApp/FlaskApp/venv/lib/python3.8/site-packages/")

from FlaskApp import app as application
application.secret_key = 'secret key stuff'

Here are some details about my environment:
Ubuntu 20.04.1 LTS
Apache/2.4.41 (Ubuntu)
Python 3.8.5 (installed in a virtual environment)

Any thoughts would be greatly appreciated!


Solution

  • It appears that the python interpreter is compiled into the mod_wsgi.so file. An old version, that included python2, was being pointed to by Apache. To fix it I did the following:

    1. Removed the old version of mod_wsgi by doing sudo apt-get remove libapache2-mod-wsgi
    2. modified /etc/apache2/mods-available/mod_wsgi.load to point to the library (.so) file in my virtual environment. The contents of mod_wsgi looked like this:
    LoadModule wsgi_module /var/www/FlaskApp/FlaskApp/venv/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so
    

    I suspect that modifying it here points all Apache virtual hosts to this python virtual environment, which isn't really ideal. It would be better if each Apache virtual host pointed to its own python environment.

    1. Modified my wsgi file to work with the new version of python. Here are the contents:
    import sys
    import logging
    logging.basicConfig(stream=sys.stderr)
    sys.path.insert(0,"/var/www/FlaskApp/")
    sys.path.insert(0,"/var/www/FlaskApp/FlaskApp/venv/lib/python3.8/site-packages/")
    
    from FlaskApp import app as application
    application.secret_key = 'secret key stuff'
    
    1. Changed the local imports in my __init__.py file to be preceeded by a dot(.)

    Following these changes the site is now working as expected.