(!) Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.

Source code changes to support Python 3

Description: Once dependencies have been transitioned, it's time to make source code changes to your package to support Python 3.

Tutorial Level: INTERMEDIATE

Next Tutorial: Build your package using Python 3

This tutorial is part of a series about transitioning a ROS 1 package to Python 3.

Source code changes to your package

Some changes will need to be made to your package to support Python 3. This includes changes in actual Python code, changes to how dependencies are specified, and changes to how Python scripts get installed.

Changing Python files

There are syntactical differences between Python 2 and Python 3. While this task is not specific to ROS, this ROS wiki page has a collection of code snippets that show how to make code compatible with both Python 2 and Python 3. For more detailed instructions, follow the official Python guide to porting to Python 3.

Changing dependencies in your package.xml

You should have made a list of rosdep keys and their Python 3 equivalents in the previous tutorial. If your package depends on any rosdep keys for Python modules, those keys will need to be changed in its package.xml.

If you decided to use the same branch for Melodic and Noetic, then your package must use conditional dependencies. Otherwise, the rosdep keys can be directly replaced

Conditional Dependencies

Conditional dependencies are a way for your package to change its dependencies depending on the environment. This is a new feature in the format 3 specification.

package.xml files can be in one of three formats: format 1, format 2, and format 3. If your package currently uses format 1, then transition it to format 2 before continuing.

To make your package.xml use format 3, first make the first 3 lines of your package.xml look like the following:

   1 <?xml version="1.0"?>
   2 <?xml-model
   3   href="http://download.ros.org/schema/package_format3.xsd"
   4   schematypens="http://www.w3.org/2001/XMLSchema"?>
   5 <package format="3">

The important part is format attribute on the <package> tag. The link to the XML schema helps automated tools validate this file, which is recommended but not required.

Next it's time to make dependencies conditional. The environment variable to use is ROS_PYTHON_VERSION. This variable is either 2 or 3, matching the major version of Python used by ROS.

For example, if there is currently a dependency on python-paramiko like the following:

   1 <exec_depend>python-paramiko</exec_depend>

Duplicate the tag, changing the key in the duplicate to be the Python 3 equivalent. Then add condition attributes which check the value of ROS_PYTHON_VERSION. The result should look like the following:

   1 <exec_depend condition="$ROS_PYTHON_VERSION == 2">python-paramiko</exec_depend>
   2 <exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-paramiko</exec_depend>

For a complete example of going from format 2 to format 3 with conditional dependencies, see this pull request to catkin.

Direct replacement

If you are using a different branch for Python 2 and Python 3, then the task becomes easier. Just replace all rosdep keys providing Python 2 modules with Python 3 equivalents. There is no need to change the format version of your package.xml.

Changing shebangs

The first line of an executable Python script, called a Shebang, picks the Python interpreter the script will run as. Python PEP 394 has recommendations about how this line should be specified.

The shebang of an installed Python script should be rewritten to specific versions. For example, if the script uses Python 2 it should have a shebang referencing python2, or if it uses Python 3 the shebang should reference python3. catkin provides a CMake function catkin_install_python() which will do this for you.

In all executable Python scripts, make sure the shebang is

#!/usr/bin/env python

Then in your CMakeLists.txt call catkin_install_python().

catkin_install_python(PROGRAMS scripts/my_executable_python_script.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

Python scripts which are only meant to be imported should not have a shebang.

Running Python scripts

If Python scripts have been installed with re-written shebangs, then they can be invoked directly. However, in some cases when building multiple packages in a single Devel space, scripts can be invoked from the source space. When this happens the script's shebang has not been re-written, and python will be invoked instead of python3. In general, tests and CMake logic should invoke scripts with python2 or python3 rather than relying on the shebang. Python scripts executing other Python scripts should use sys.executable.

Next Tutorial: Build your package using Python 3

Wiki: UsingPython3/SourceCodeChanges (last edited 2019-08-23 20:06:01 by MaryaBelanger)