Documentation

Documentation is important for users writing OCSClients that can interact with your new Agent. When writing a new Agent you must document the Tasks and Processes with appropriate docstrings. Additionally a page must be created within the docs to describe the Agent and provide other key information such as configuration file examples. You should aim to be a thorough as possible when writing documentation for your Agent.

Task and Process Documentation

Each Task and Process within an Agent must be accompanied by a docstring. Here is a complete example of a well documented Task (or Process):

@ocs_agent.param('arg1', type=bool)
@ocs_agent.param('arg2', default=7, type=int)
def demo(self, session, params):
    """demo(arg1=None, arg2=7)

    **Task** (or **Process**) - An example task docstring for illustration purposes.

    Parameters:
        arg1 (bool): Useful argument 1.
        arg2 (int, optional): Useful argument 2, defaults to 7. For details see
                             :func:`socs.agent.demo_agent.DemoClass.detailing_method`

    Examples:
        Example for calling in a client::

            client.demo(arg1=False, arg2=5)

    Notes:
        An example of the session data::

            >>> response.session['data']
            {"fields":
                {"Channel_05": {"T": 293.644, "R": 33.752, "timestamp": 1601924482.722671},
                 "Channel_06": {"T": 0, "R": 1022.44, "timestamp": 1601924499.5258765},
                 "Channel_08": {"T": 0, "R": 1026.98, "timestamp": 1601924494.8172355},
                 "Channel_01": {"T": 293.41, "R": 108.093, "timestamp": 1601924450.9315426},
                 "Channel_02": {"T": 293.701, "R": 30.7398, "timestamp": 1601924466.6130798}
                }
            }
    """
    pass

Keep reading for more details on what’s going on in this example.

Overriding the Method Signature

session and params are both required parameters when writing an OCS Task or Process, but both should be hidden from users writing OCSClients. When documenting a Task or Process, the method signature should be overridden to remove both session and params, and to include any parameters your Task or Process might take. This is done in the first line of the docstring, by writing the method name, followed by the parameters in parentheses. In the above example that looks like:

def demo(self, session, params=None):
    """demo(arg1=None, arg2=7)"""

This will render the method description as delay_task(arg1=None, arg2=7) within Sphinx, rather than delay_task(session, params=None). The default values should be put in this documentation. If a parameter is required, set the param to None in the method signature. For more info on the @ocs_agent.param decorator see Operation Parameters.

Keyword Arguments

Internal to OCS the keyword arguments provided to an OCSClient are passed as a dict to params. For the benefit of the end user, these keyword arguments should be documented in the Agent as if passed as such. So the docstring should look like:

Parameters:
    arg1 (bool): Useful argument 1.
    arg2 (int, optional): Useful argument 2, defaults to 7. For details see
                         :func:`socs.agent.lakeshore.LakeshoreClass.the_method`

Examples

Examples should be given using the “Examples” heading when it would improve the clarity of how to interact with a given Task or Process:

Examples:
    Example for calling in a client::

        client.demo(arg1=False, arg2=5)

Session Data

The session.data object structure is left up to the Agent author. As such, it needs to be documented so that OCSClient authors know what to expect. If your Task or Process makes use of session.data, provide an example of the structure under the “Notes” heading. On the OCSClient end, this session.data object is returned in the response under response.session['data']. This is how it should be presented in the example docstrings:

Notes:
    An example of the session data::

        >>> response.session['data']
        {"fields":
            {"Channel_05": {"T": 293.644, "R": 33.752, "timestamp": 1601924482.722671},
             "Channel_06": {"T": 0, "R": 1022.44, "timestamp": 1601924499.5258765},
             "Channel_08": {"T": 0, "R": 1026.98, "timestamp": 1601924494.8172355},
             "Channel_01": {"T": 293.41, "R": 108.093, "timestamp": 1601924450.9315426},
             "Channel_02": {"T": 293.701, "R": 30.7398, "timestamp": 1601924466.6130798}
            }
        }

For more details on the session.data object see session.data.

Agent Reference Pages

Now that you have documented your Agent’s Tasks and Processes appropriately we need to make the page that will display that documentation. Agent reference pages are kept in ocs/docs/agents/. Each Agent has a separate .rst file. Each Agent reference page must contain:

  • Brief description of the Agent

  • Example ocs-site-config configuration block

  • Example docker compose configuration block (if Agent is dockerized)

  • Agent API reference

Reference pages can also include:

  • Detailed description of Agent or related material

  • Example client scripts

  • Supporting APIs

Here is a template for an Agent documentation page. Text starting with a ‘#’ is there to guide you in writing the page and should be replaced or removed. Unneeded sections should be removed.

.. highlight:: rst

.. _template:

==============
Template Agent
==============

# A brief description of the Agent.

.. argparse::
   :module: agents.template.template_agent
   :func: make_parser
   :prog: template_agent.py

Dependencies
------------

# Any external dependencies for agent. Omit if there are none, or they are
# included in the main requirements.txt file.

Configuration File Examples
---------------------------

Below are configuration examples for the ocs config file and for running the
Agent in a docker container.

OCS Site Config
````````````````

An example site-config-file block::

    {'agent-class': 'TemplateAgent',
       'instance-id': 'template',
       'arguments': [['--argument-1', 'value1'],
                     ['--argument-2', 42],
                     ['--argument-3']]},

Docker Compose
``````````````

An example docker compose configuration::

    ocs-template:
        image: simonsobs/ocs-template-agent:latest
        hostname: ocs-docker
        environment:
          - LOGLEVEL=info
        volumes:
          - ${OCS_CONFIG_DIR}:/config

Description
-----------

# Detailed description of the Agent. Include any details the users or developers
# might find valuable.

Subsection
``````````

# Use subsections where appropriate.

Agent API
---------

# Autoclass the Agent, this is for users to reference when writing clients.

.. autoclass:: agents.template.template_agent.TemplateAgent
    :members:

Example Clients
---------------

# If an example client makes use of the Agent more clear, include here in a code block::

    from ocs.ocs_client import OCSClient
    client = OCSClient('template')
    client.task()

Supporting APIs
---------------

# Autodoc any code supporting the Agent. This is for developers to reference
# when working on the Agent. :noindex: should be used here if code is also
# indexed in the main API page.

.. autoclass:: ocs.agent.template.Template1
    :members:
    :noindex:

.. autoclass:: ocs.agent.template.Template2
    :members:
    :noindex: