Handling of setup.py
¶
If your ROS package contains python modules and scripts to install,
you need to define the installation process and a way to make
the scripts accessible in the develspace.
The python ecosystem defines installation standards in the
distutils
or setuputils
libraries. With those libraries,
packages define the installation files in a file called setup.py
in the project root. The setup.py file uses Python to describe the
Python content of the stack.
We recommend to prefer distutils package over setuptools/distribute, because with distutils we can avoid the creation of egg-info folders in the project source folder. The setup.cfg file of distutils2 is not supported by catkin.
Catkin allows you to specify the installation of your python files in this setup.py and reuse some of the information in your CMakeLists.txt.
You can do so by including the line:
catkin_python_setup()
in the CMakeLists.txt of your project.
catkin will execute setup.py with a hot-patched version of distutils
to read the arguments to set up the devel space, and execute setup.py
with suitable arguments to install to the catkin install space under
CMAKE_INSTALL_PREFIX
.
This means that if you execute your setup.py using:
# DO NOT USE
# python setup.py install
manually, that would install to a different location, and you would have multiple installed versions. Python will decide at runtime which one to use based on your PYTHONPATH environment variable, and it may pick the one you expect it to pick, but we recommend against having multiple installed versions in the first place. Using setup.py to create a pypi package of your catkin package currently has no support for ROS messages and services, and core ROS libraries (e.g. rospy) are not available on pypi, so this using setup.py for pypi is not very useful for ROS nodes.
For the develspace, the following setup.py arguments to setup() will be used by catkin:
from distutils.core import setup
setup(
version='...',
scripts=['bin/myscript'],
packages=['mypkg'],
package_dir={'': 'src'}
)
This creates relays for all scripts listed in scripts
to a folder
in devel space where they can be found and executed, and also relay
packages for any package listed in packages
. A relay package is a
folder with an __init__.py folder and nothing else. Importing this
folder in python will execute the contents of __init__.py, which will
in turn import the original python modules in the folder in the
sourcespace using the python exec() function.
The version will be compared to that declared in package.xml, and raise an error on mismatch.
Note
If you have written non-ROS Python packages before, you have
probably used the requires
field in the distuils setup function.
This field, however, has no meaning in ROS.
All your Python
dependencies should be specified in package.xml
as e.g.
<run_depend>python-numpy</run_depend>
(for older version 1
of package.xml) or <exec_depend>python-numpy</exec_depend>
(if you use format 2 of package.xml).
Not all Python or pip packages are mapped to ROS dependencies.
For a quick check, try running rosdep resolve python-mypackage
or rosdep resolve python-mypackage-pip
if you want to
add a dependency on mypackage
Python package. If these calls
return error, you may want to search through the
python.yaml file in rosdep for similar names. If you don’t
find the requested package, you may consider
creating a Pull request to add it.
Using package.xml in setup.py¶
Writing a setup.py file without duplicating information contained in the package.xml is possible using a catkin_pkg convenience function like this:
from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup
d = generate_distutils_setup(
packages=['mypkg'],
scripts=['bin/myscript'],
package_dir={'': 'src'}
)
setup(**d)
This will parse the package.xml and also format the fields, such that multiple authors with emails will be set nicely for setup.py, in case one distributes to pypi.
Note
ROS Users should generally not use the scripts argument, as in ROS, executables should be executed using rosrun rather than being installed to the global bin folder. One way of installing such python scripts is to add the following to the CMakeLists.txt:
catkin_install_python(PROGRAMS scripts/myscript
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
Note
See the note in previous section about the otherwise useful
field requires
that’s usually a part of distutils setup.
Do not use it in ROS.
Develspace limitations¶
For the devel space, catkin currently does not support any of the following distutils arguments:
- py_modules
- data_files
- any extention module features
From setuptools, the following args are not supported for the devel space:
- zip-safe
- entry_points
From distribute, the following args are not supported for the devel space:
- include_package_data
- exclude_package_data
- zip_safe
- entry_points
- setup_requires
- namespace_packages
- use_2to3
Those features will only work correctly for the install space.
genmsg interaction¶
genmsg is an external catkin package that provideslanguage bindings for ROS messages. When using the genmsg macro, ordering constraints exist, in that case you have to invoke the macros in this order:
project(...)
...
find_package(catkin ...)
...
catkin_python_setup()
...
generate_messages()
...
catkin_package()