.. _setup_dot_py_handling:

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.

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 or
setuptools 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 setuptools 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`_.

  .. _python.yaml file in rosdep: https://github.com/ros/rosdistro/blob/master/rosdep/python.yaml
  .. _creating a Pull request to add it: http://docs.ros.org/independent/api/rosdep/html/contributing_rules.html

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 setuptools 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 setuptools 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()
