This little tutorial was inspired by some other forum topics about Python 2 becoming deprecated in less than a year and hence users getting the following error for every app they update:
Error setting up virtualenv, one or more actions might not be able to run. Reason : DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7.
I did the following to convert one of my apps to Python 3 and I thought it would be interesting to other app developers:
Step 1: Run 2to3 on your code
Note that you don’t have to apply all suggestions that 2to3 gives. Some of the suggestions are only needed in specific circumstances. For instance, I didn’t change
for key in data.keys(): to the suggested
for key in list(data.keys()): in the file snipsTools.py from snips-app-template-py because the code doesn’t use
data.keys() as a list, for instance it doesn’t index the list.
Another option is that you use the futurize script, which makes your code compatible with both Python 2 and 3. I’m not interested in bloating my code to support a Python version that becomes deprecated in less than a year, so I didn’t use it.
Also, don’t forget to change the shebang line in the beginning of each Python file to:
If you’re using the Hermes Python library in your app, add the following in your app’s
requirements.txt (because of a bug I found in Hermes Python in step 5):
Step 2: Create a Python 3 virtual environment
The default setup.sh script from the Snips app template creates a virtual environment for Python 2. Changing this to Python 3 is easy, but I also wanted to handle the situation where my app’s user has his Python 2 version of the app installed and gets a new Python 3 virtual environment after he updates the app, without any remnants of the previous Python 2 environment. So after extending and cleaning up
setup.sh, this resulted in the following script:
#/usr/bin/env bash -e # Copy config.ini.default if config.ini doesn't exist. if [ ! -e config.ini ] then cp config.ini.default config.ini fi PYTHON=`which python3` VENV=venv if [ -f "$PYTHON" ] then if [ ! -d $VENV ] then # Create a virtual environment if it doesn't exist. $PYTHON -m venv $VENV else if [ -e $VENV/bin/python2 ] then # If a Python2 environment exists, delete it first # before creating a new Python 3 virtual environment. rm -r $VENV $PYTHON -m venv $VENV fi fi # Activate the virtual environment and install requirements. . $VENV/bin/activate pip3 install -r requirements.txt else >&2 echo "Cannot find Python 3. Please install it." fi
Step 3: Test your code
Test your changes thoroughly on your Snips machine. Test all actions, especially where you have changed code suggested by 2to3. But 2to3 can’t find all needed changes. For instance, Python 2 and 3 differ a lot in how they handle strings, so that’s an area you should especially pay attention to in your tests (see also step 5).
Step 4: Upload your code
Commit your changes to Git and push them to your GitHub repository. Thanks to the new setup script, there are three situations now when your users update their skills:
- A new user installs your app for the first time. The script creates a Python 3 virtual environment.
- The Python 2 app updates to Python 3. The script deletes the Python 2 virtual environment and creates a Python 3 virtual environment.
- (Later when you keep updating your app) The Python 3 app gets an update. The script already has a Python 3 virtual environment.
In each of these three situations, a Python 3 environment is created, the script activates the virtual environment and installs the requirements. You don’t get the deprecation warning anymore. After this, the Snips skill server runs your actions as Python 3 code, as you can see with
ps aux|grep python3.