Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

diagnostic_updater: Added documentation of the Python interface. #399

Open
wants to merge 2 commits into
base: noetic-devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions diagnostic_updater/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
doc/html
doc/manifest.yaml
92 changes: 92 additions & 0 deletions diagnostic_updater/doc/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-

import os, sys, time
from os.path import abspath, dirname, join

from docutils import nodes
from sphinx.ext import intersphinx

import catkin_pkg.package

catkin_dir = dirname(dirname(abspath(__file__)))
catkin_package = catkin_pkg.package.parse_package(join(catkin_dir, catkin_pkg.package.PACKAGE_MANIFEST_FILENAME))

project = catkin_package.name
copyright = time.strftime("%Y") + ', Czech Technical University in Prague'
author = ", ".join([a.name for a in catkin_package.authors])
version = catkin_package.version
release = catkin_package.version

import catkin_sphinx
html_theme_path = [catkin_sphinx.get_theme_path()]

# Use ROS theme
html_theme = 'ros-theme'

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.extlinks',
'sphinx.ext.viewcode']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The master toctree document.
master_doc = 'index'

# Resolve ROS message and service dependencies
ros_distro = os.getenv('ROS_DISTRO', 'latest')
ros_api_base = 'https://docs.ros.org/en/%s/api/'
ros_api = ros_api_base % ros_distro

# Example configuration for intersphinx: refer to the Python standard library.
python_version = '{}.{}'.format(sys.version_info.major, sys.version_info.minor)
intersphinx_mapping = {
'python': ('https://docs.python.org/{}/'.format(python_version), None),
'genpy': (ros_api + 'genpy/html', None),
}

extlinks = {
'diagnostic_msgs': (ros_api + 'diagnostic_msgs/html/msg/%s.html', 'diagnostic_msgs/'),
}

# Produce both class and constructor doc comments
autoclass_content = 'both'


def ros_msg_reference(app, env, node, contnode):
text_node = next(iter(contnode.traverse(lambda n: n.tagname == '#text')))
parts = text_node.astext().split('.')
# diagnostic_msgs.msg.DiagnosticStatus
if len(parts) == 3:
pkg, obj_type, obj = parts
# diagnostic_msgs.msg._DiagnosticStatus.DiagnosticStatus
elif len(parts) == 4:
pkg, obj_type, module, obj = parts
if "_" + obj != module:
return intersphinx.missing_reference(app, env, node, contnode)
else:
return intersphinx.missing_reference(app, env, node, contnode)
if obj_type not in ("msg", "srv"):
return intersphinx.missing_reference(app, env, node, contnode)
target = ros_api + '{}/html/{}/{}.html'.format(pkg, obj_type, obj)
ref_node = nodes.reference()
ref_node['refuri'] = target
title = '{}/{}'.format(pkg, obj)
text_node = nodes.literal(title, title)
text_node['classes'] = ['xref', 'ros', 'ros-' + obj_type]
ref_node += text_node
return ref_node


# Backport of fix for issue https://github.com/sphinx-doc/sphinx/issues/2549. Without it, :ivar: fields wrongly resolve cross-references.
from sphinx.domains.python import PyObject
PyObject.doc_field_types[list(map(lambda f: f.name == 'variable', PyObject.doc_field_types)).index(True)].rolename = None


def setup(app):
app.connect("missing-reference", ros_msg_reference)

21 changes: 21 additions & 0 deletions diagnostic_updater/doc/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Welcome to diagnostic_updater documentation!
============================================

.. toctree::
:maxdepth: 2

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

Module diagnostic\_updater
==========================

.. automodule:: diagnostic_updater
:members:
:undoc-members:
:show-inheritance:

2 changes: 2 additions & 0 deletions diagnostic_updater/mainpage.dox
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ publication. These libraries are commonly used by device drivers as part of the
statistics automatically when publications are made to a topic.

Example uses of these classes can be found in \ref src/example.cpp.

The Python API is described in <a href="python/index.html">python</a> subfolder.

*/
12 changes: 8 additions & 4 deletions diagnostic_updater/package.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<package>
<package format="2">
<name>diagnostic_updater</name>
<version>1.11.0</version>
<description>diagnostic_updater contains tools for easily updating diagnostics. it is commonly used in device drivers to keep track of the status of output topics, device status, etc.</description>
Expand All @@ -22,15 +22,19 @@
<build_depend>rostest</build_depend>
<build_depend>std_msgs</build_depend>

<run_depend>diagnostic_msgs</run_depend>
<run_depend>roscpp</run_depend>
<run_depend>std_msgs</run_depend>
<exec_depend>diagnostic_msgs</exec_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>std_msgs</exec_depend>

<doc_depend>rosdoc_lite</doc_depend>
<doc_depend>python3-catkin-sphinx</doc_depend>

<!-- <test_depend>roscpp</test_depend> -->
<!-- <test_depend>diagnostic_msgs</test_depend> -->
<!-- <test_depend>std_msgs</test_depend> -->

<export>
<rosdoc config="rosdoc.yaml"/>
<architecture_independent/>
</export>
</package>
5 changes: 5 additions & 0 deletions diagnostic_updater/rosdoc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- builder: doxygen
name: C++ API
- builder: sphinx
sphinx_root_dir: doc
output_dir: python
37 changes: 37 additions & 0 deletions diagnostic_updater/src/diagnostic_updater/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,44 @@
# POSSIBILITY OF SUCH DAMAGE.

# -*- coding: utf-8 -*-

"""
`diagnostic_updater` contains assorted Python classes to assist in diagnostic
publication. These libraries are commonly used by device drivers as part of the diagnostics
toolchain. The main parts of `diagnostic_updater` are:

- :class:`DiagnosticStatusWrapper`, a wrapper providing
convenience functions for working with :class:`diagnostics_msgs.msg.DiagnosticStatus`.

- :class:`Updater`, a class for managing periodic publishing of the
:class:`DiagnosticStatusWrapper` output by a set of :class:`DiagnosticTask`.

- :class:`TopicDiagnostic` and :class:`HeaderlessTopicDiagnostic` for calculating and
publishing statistics on timestamps and publication frequencies, and
their corresponding :class:`DiagnosedPublisher` and :class:`HeaderlessDiagnosedPublisher`
to update the statistics automatically when publications are made to a topic.

Example uses of these classes can be found in `src/example.py`.
"""

from ._diagnostic_status_wrapper import *
from ._diagnostic_updater import *
from ._update_functions import *
from ._publisher import *

__all__ = [
'DiagnosticStatusWrapper',
'DiagnosticTask',
'FunctionDiagnosticTask',
'CompositeDiagnosticTask',
'DiagnosticTaskVector',
'Updater',
'HeaderlessTopicDiagnostic',
'TopicDiagnostic',
'DiagnosedPublisher',
'FrequencyStatusParam',
'FrequencyStatus',
'TimeStampStatusParam',
'TimeStampStatus',
'Heartbeat',
]
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@
ERROR = DiagnosticStatus.ERROR

class DiagnosticStatusWrapper(DiagnosticStatus):
""" Wrapper for the diagnostic_msgs::DiagnosticStatus message that makes it
""" Wrapper for the :diagnostic_msgs:`DiagnosticStatus` message that makes it
easier to update.

This class handles common string formatting and vector handling issues
for filling the diagnostic_msgs::DiagnosticStatus message. It is a subclass of
diagnostic_msgs::DiagnosticStatus, so it can be passed directly to
for filling the :diagnostic_msgs:`DiagnosticStatus` message. It is a subclass of
:diagnostic_msgs:`DiagnosticStatus`, so it can be passed directly to
diagnostic publish calls.
"""

Expand All @@ -63,19 +63,21 @@ def __init__(self, *args, **kwds):
The available fields are:
level,name,message,hardware_id,values

@param args: complete set of field values, in .msg order
@param kwds: use keyword arguments corresponding to message field names
to set specific fields.
:param args: complete set of field values, in .msg order
:param kwds: use keyword arguments corresponding to message field names
to set specific fields.
"""
DiagnosticStatus.__init__(self, *args, **kwds)


def summary(self, *args):
""" Fills out the level and message fields of the DiagnosticStatus.
""" Fills out the level and message fields of the :diagnostic_msgs:`DiagnosticStatus`.

Usage:
summary(diagnostic_status): Copies the summary from a DiagnosticStatus message
summary(lvl,msg): sets from lvl and messages

`summary(diagnostic_status)`: Copies the summary from a :diagnostic_msgs:`DiagnosticStatus` message

`summary(lvl,msg)`: sets from lvl and messages
"""
if len(args)==1:
self.level = args[0].level
Expand All @@ -94,10 +96,10 @@ def clearSummary(self):
def mergeSummary(self, *args):
""" Merges a level and message with the existing ones.

It is sometimes useful to merge two DiagnosticStatus messages. In that case,
It is sometimes useful to merge two :diagnostic_msgs:`DiagnosticStatus` messages. In that case,
the key value pairs can be unioned, but the level and summary message
have to be merged more intelligently. This function does the merge in
an intelligent manner, combining the summary in *this, with the one
an intelligent manner, combining the summary in this, with the one
that is passed in.

The combined level is the greater of the two levels to be merged.
Expand All @@ -107,8 +109,10 @@ def mergeSummary(self, *args):
zero, the new message is ignored.

Usage:
mergeSummary(diagnostic_status): merge from a DiagnosticStatus message
mergeSummary(lvl,msg): sets from lvl and msg

`mergeSummary(diagnostic_status)`: merge from a :diagnostic_msgs:`DiagnosticStatus` message

`mergeSummary(lvl,msg)`: sets from lvl and msg
"""
if len(args)==1:
lvl = args[0].level
Expand All @@ -131,13 +135,11 @@ def mergeSummary(self, *args):
def add(self, key, val):
""" Add a key-value pair.

This method adds a key-value pair. Any type that has a << stream
operator can be passed as the second argument. Formatting is done
using a std::stringstream.
This method adds a key-value pair.

@type key string
@param key Key to be added.
@type value string
@param value Value to be added.
:type key: string
:param key: Key to be added.
:type any: string
:param value: Value to be added.
"""
self.values.append(KeyValue(key,str(val)))
Loading