cPanel App runs on Python2 instead of Python3
Question:
I have a VPS Hosting in cPanel, and a Flask-App.
I followed the instructions of How to install WSGI Application in cPanel.
Everything is working fine, when I run the application using the terminal, but when I open the App URL, it shows the following error:
Traceback (most recent call last):
File "/opt/cpanel/ea-ruby24/root/usr/share/passenger/helper-scripts/wsgi-loader.py", line 369, in <module>
app_module = load_app()
File "/opt/cpanel/ea-ruby24/root/usr/share/passenger/helper-scripts/wsgi-loader.py", line 76, in load_app
return imp.load_source('passenger_wsgi', startup_file)
File "/home/qsemh/Maidan/passenger_wsgi.py", line 8, in <module>
wsgi = imp.load_source('wsgi', 'wsgi.py')
File "wsgi.py", line 1, in <module>
from flaskr import create_app
File "/home/qsemh/Maidan/flaskr/__init__.py", line 133
print(f"Validate {len(users)} Users At {current_time}")
^
SyntaxError: invalid syntax
So I’ve decided to create a simpler app in order to detect the issue, the app is as following :
passenger_wsgi.py
#!/usr/bin/env python3
import sys
from flask import Flask
application = Flask(__name__)
application.route("/")
def index():
return sys.version
When I run this simple Application Using the URL it shows the following as a respond :
2.7.5 (default, Apr 2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
even though I’ve used the shebang #!/usr/bin/env python3
at the start of the file, and when I run it using the terminal, it works as if it using python3.
I’ve tried changing the shebang to the following formats :
#!/usr/bin/python3
#!/usr/bin/env 'python3'
but they gave the same result.
What is the problem here, and How can I solve it?
Answers:
I’ve found the Correct approach to solve this issue;
Basically, I only needed to add the following lines at the beginning of my passenger_wsgi.py file :
import os
INTERP = "/usr/bin/python3"
if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
so the final result would be :
passenger_wsgi.py
#!/usr/bin/env python3
import sys
import os
# Solution
INTERP = "/usr/bin/python3"
if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
from flask import Flask
application = Flask(__name__)
application.route("/")
def index():
return sys.version
and the respond is correctly as I intended in the first place:
3.6.8 (default, Apr 2 2020, 13:34:55) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
This answer might be for some cPanel users. My cPanel is using passenger and wsgi, and even though my cPanel Python application is set to use python 3.9. it was running 2.7.5. Worse, it set all the 2.7 folders in the path.
So I ended up with this helper script called from
passenger_wsgi.py
. I’m moved all the code out of this file into an import because this file may get blown away and re-created in some cases. It’s not safe to rely on code in this file surviving. It’s an auto generated file.
Put set_python_environment.py
file in the same directory as passenger_wsgi.py
set_python_environment.py
# -*- coding: UTF-8 -*-
# insert these lines into passenger_wsgi.py if that file is rebuilt:
# import set_python_environment
# set_python_environment.upgrade_python()
import sys
import os
def upgrade_python():
try:
python_interpreter = "/home/username/virtualenv/YourApplicationPath/3.9/bin/python3.9_bin"
if sys.executable != python_interpreter:
print('switching from ' + sys.version + ' to ' + python_interpreter + '...')
print('directory: ' + os.path.dirname(__file__))
print('file: ' + __file__)
print('arg 0: ' + sys.argv[0])
# rebuild the env path variable
print('old system path:n' + "n".join(str(x) for x in sys.path))
print('n')
for x in sys.path:
sys.path.remove(x)
sys.path.append('/opt/cpanel/ea-ruby24/root/usr/share/passenger/helper-scripts')
# App 3956 output: /usr/lib/python2.7/site-packages/pyzor-1.0.0-py2.7.egg
# App 3956 output: /usr/lib64/python27.zip
# App 3956 output: /usr/lib64/python2.7
sys.path.append('/home/username/virtualenv/YourApplicationPath/3.9/lib64/python3.9')
# App 3956 output: /usr/lib64/python2.7/plat-linux2
# App 3956 output: /usr/lib64/python2.7/lib-tk
# App 3956 output: /usr/lib64/python2.7/lib-old
# App 3956 output: /usr/lib64/python2.7/lib-dynload
# App 3956 output: /home/username/.local/lib/python2.7/site-packages
# App 3956 output: /usr/lib64/python2.7/site-packages
sys.path.append('/home/username/virtualenv/YourApplicationPath/3.9/lib64/python3.9/site-packages')
# App 3956 output: /usr/lib64/python2.7/site-packages/gtk-2.0
# App 3956 output: /usr/lib/python2.7/site-packages
sys.path.append('/home/username/virtualenv/YourApplicationPath/3.9/lib/python3.9/site-packages')
sys.path.append('/home/username/virtualenv/YourApplicationPath/3.9/bin')
print('new system path:n' + "n".join(str(x) for x in sys.path))
print('n')
os.execl(python_interpreter, python_interpreter, *sys.argv)
else:
print('...continuing with ' + sys.executable)
except Exception as e:
print(str(e))
Modified passenger_wsgi.py
# -*- coding: UTF-8 -*-
import sys
import os
import imp
import set_python_environment
set_python_environment.upgrade_python()
sys.path.insert(0, os.path.dirname(__file__))
wsgi = imp.load_source('wsgi', 'app.py')
application = wsgi.app
In order to get the right path, I typed whereis python
in the ssh environment after running the source
command given on the python application page, to find the location of all the python versions, and the one ending in bin
turned out to be the one which actually works.
I have a VPS Hosting in cPanel, and a Flask-App.
I followed the instructions of How to install WSGI Application in cPanel.
Everything is working fine, when I run the application using the terminal, but when I open the App URL, it shows the following error:
Traceback (most recent call last):
File "/opt/cpanel/ea-ruby24/root/usr/share/passenger/helper-scripts/wsgi-loader.py", line 369, in <module>
app_module = load_app()
File "/opt/cpanel/ea-ruby24/root/usr/share/passenger/helper-scripts/wsgi-loader.py", line 76, in load_app
return imp.load_source('passenger_wsgi', startup_file)
File "/home/qsemh/Maidan/passenger_wsgi.py", line 8, in <module>
wsgi = imp.load_source('wsgi', 'wsgi.py')
File "wsgi.py", line 1, in <module>
from flaskr import create_app
File "/home/qsemh/Maidan/flaskr/__init__.py", line 133
print(f"Validate {len(users)} Users At {current_time}")
^
SyntaxError: invalid syntax
So I’ve decided to create a simpler app in order to detect the issue, the app is as following :
passenger_wsgi.py
#!/usr/bin/env python3
import sys
from flask import Flask
application = Flask(__name__)
application.route("/")
def index():
return sys.version
When I run this simple Application Using the URL it shows the following as a respond :
2.7.5 (default, Apr 2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
even though I’ve used the shebang #!/usr/bin/env python3
at the start of the file, and when I run it using the terminal, it works as if it using python3.
I’ve tried changing the shebang to the following formats :
#!/usr/bin/python3
#!/usr/bin/env 'python3'
but they gave the same result.
What is the problem here, and How can I solve it?
I’ve found the Correct approach to solve this issue;
Basically, I only needed to add the following lines at the beginning of my passenger_wsgi.py file :
import os
INTERP = "/usr/bin/python3"
if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
so the final result would be :
passenger_wsgi.py
#!/usr/bin/env python3
import sys
import os
# Solution
INTERP = "/usr/bin/python3"
if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
from flask import Flask
application = Flask(__name__)
application.route("/")
def index():
return sys.version
and the respond is correctly as I intended in the first place:
3.6.8 (default, Apr 2 2020, 13:34:55) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
This answer might be for some cPanel users. My cPanel is using passenger and wsgi, and even though my cPanel Python application is set to use python 3.9. it was running 2.7.5. Worse, it set all the 2.7 folders in the path.
So I ended up with this helper script called from
passenger_wsgi.py
. I’m moved all the code out of this file into an import because this file may get blown away and re-created in some cases. It’s not safe to rely on code in this file surviving. It’s an auto generated file.
Put set_python_environment.py
file in the same directory as passenger_wsgi.py
set_python_environment.py
# -*- coding: UTF-8 -*-
# insert these lines into passenger_wsgi.py if that file is rebuilt:
# import set_python_environment
# set_python_environment.upgrade_python()
import sys
import os
def upgrade_python():
try:
python_interpreter = "/home/username/virtualenv/YourApplicationPath/3.9/bin/python3.9_bin"
if sys.executable != python_interpreter:
print('switching from ' + sys.version + ' to ' + python_interpreter + '...')
print('directory: ' + os.path.dirname(__file__))
print('file: ' + __file__)
print('arg 0: ' + sys.argv[0])
# rebuild the env path variable
print('old system path:n' + "n".join(str(x) for x in sys.path))
print('n')
for x in sys.path:
sys.path.remove(x)
sys.path.append('/opt/cpanel/ea-ruby24/root/usr/share/passenger/helper-scripts')
# App 3956 output: /usr/lib/python2.7/site-packages/pyzor-1.0.0-py2.7.egg
# App 3956 output: /usr/lib64/python27.zip
# App 3956 output: /usr/lib64/python2.7
sys.path.append('/home/username/virtualenv/YourApplicationPath/3.9/lib64/python3.9')
# App 3956 output: /usr/lib64/python2.7/plat-linux2
# App 3956 output: /usr/lib64/python2.7/lib-tk
# App 3956 output: /usr/lib64/python2.7/lib-old
# App 3956 output: /usr/lib64/python2.7/lib-dynload
# App 3956 output: /home/username/.local/lib/python2.7/site-packages
# App 3956 output: /usr/lib64/python2.7/site-packages
sys.path.append('/home/username/virtualenv/YourApplicationPath/3.9/lib64/python3.9/site-packages')
# App 3956 output: /usr/lib64/python2.7/site-packages/gtk-2.0
# App 3956 output: /usr/lib/python2.7/site-packages
sys.path.append('/home/username/virtualenv/YourApplicationPath/3.9/lib/python3.9/site-packages')
sys.path.append('/home/username/virtualenv/YourApplicationPath/3.9/bin')
print('new system path:n' + "n".join(str(x) for x in sys.path))
print('n')
os.execl(python_interpreter, python_interpreter, *sys.argv)
else:
print('...continuing with ' + sys.executable)
except Exception as e:
print(str(e))
Modified passenger_wsgi.py
# -*- coding: UTF-8 -*-
import sys
import os
import imp
import set_python_environment
set_python_environment.upgrade_python()
sys.path.insert(0, os.path.dirname(__file__))
wsgi = imp.load_source('wsgi', 'app.py')
application = wsgi.app
In order to get the right path, I typed whereis python
in the ssh environment after running the source
command given on the python application page, to find the location of all the python versions, and the one ending in bin
turned out to be the one which actually works.