How to Markup a SPEC Macro File

  1. start with SPEC macro file that is not marked up
  2. create a Sphinx documentation project
  3. apply markup
  4. test

Tip

In addition to the Sphinx documentation (http://sphinx.pocoo.org), a good reference how to document your macros can be found here: http://stackoverflow.com/questions/4547849/good-examples-of-python-docstrings-for-sphinx but a Google search for sphinx python docstrings examples will turn up a wealth of alternatives.

Basic SPEC Macro file

This example is a SPEC macro file from the APS subversion repository: https://subversion.xray.aps.anl.gov/spec/macros/trunk/common/hkl_ioc.mac because it is simple, brief, does not contain references to other macro files, provides its documentation in SPEC comments, and has not been marked up previously for documentation with Sphinx. Here is the file hkl_ioc.mac in its entirety.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#===============================================================================
#**************SPEC macros for the Advanced Photon Source***********************
#===============================================================================
#
# Beamline/Sector: 4ID
# 
# Macro Package: hkl_ioc.mac
#
# Version: 1.0 (August,2005)
#
# Description: A user defined calcHKL to write the current HKL postion to a
#              soft IOC. It requires spec softioc running.
#
# Written by: X. Jiao 08/08/2005
# 
# Modified by: 
#
# User macros: ioc_HKL -> to turn on/off the feature of putting HKL to shared
#                           memory.
#
# Internal macros: ioc_put_HKL -> write HKL to the soft IOC
#
# Modification history:
# 
#$Log$
#Revision 1.3  2006/05/22 20:34:35  jiaox
#removed unsed lines in ioc_HKL.
#
#Revision 1.2  2006/05/11 17:46:31  jiaox
#Added CVS Log entry.
#
#===============================================================================

#===============================================================================
# preload check/setting here
#===============================================================================

cdef("user_save_HKL","","ioc_HKL")
cdef("calcHKL","calc(2); user_save_HKL;","ioc_HKL")

#===============================================================================
# global variables defined here
#===============================================================================
if( unset("SIOC_PV") ) {
global SIOC_PV
local foo tmp[]
SIOC_PREFIX="4id"
unix("hostname | cut -f1 -d.",foo)
split(foo,tmp,"\n")
foo=tmp[0]
SIOC_PV = sprintf("%s:%s:spec",SIOC_PREFIX,foo)
printf("Spec soft IOC PV(SIOC_PV): %s",SIOC_PV)
}

#===============================================================================
# user macros defined here
#===============================================================================
def ioc_HKL '{
     
    if($# != 1) { eprint "Usage: ioc_HKL on/off ";exit}
    
    
    if(("$1" == "on")) {
       cdef("user_save_HKL","ioc_put_HKL","ioc_HKL","0x20")
       print "Now put HKL to softioc."
       exit
    }
    if(("$1" == "off")) {
       cdef("user_save_HKL","","ioc_HKL","delete")
       print "Stop put HKL to softioc."
       exit
    }
    eprint "Usage: ioc_HKL on/off "
}'


#===============================================================================
# internal macros defined here
#===============================================================================
def ioc_put_HKL '
    epics_put(sprintf("%s:H",SIOC_PV),H)
    epics_put(sprintf("%s:K",SIOC_PV),K)
    epics_put(sprintf("%s:L",SIOC_PV),L)
    epics_put(sprintf("%s:NPTS",SIOC_PV),NPTS)
'       
     
  

Create a Sphinx Project

Make a project directory and change directory into it. (On my development system, this directory is called ../markup_example.) Copy the file above into this directory with the name hkl_ioc.mac. Then run:

sphinx-quickstart

Take most of the defaults. These are the non-defaults for the example project:

prompt response
> Project name: example
> Author name(s): SPEC Macro Writer
> Project version: 1
> autodoc: automatically insert docstrings from modules (y/N) [n]: y
> viewcode: include links to the source code of documented Python objects (y/N) [n]: y

Edit the document index.rst so it looks like this:

.. example documentation master file, created by
   sphinx-quickstart on Sun Jul 15 17:54:46 2012.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to example's documentation!
===================================

.. autospecmacro:: hkl_ioc.mac

Contents:

.. toctree::
   :maxdepth: 2



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

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

Edit conf.py and make these changes:

change directions
sys.path.insert(0, os.path.abspath('..')) replace line 19
extensions.append( 'sphinxcontrib.specdomain' ) insert after line 28

The revised file should look like this file: ../markup_example/conf.py.

Now, build the documentation by typing:

make html
firefox _build/html/index.html &

You should expect a page that looks like this figure:

view of original hkl_ioc.mac HTML documentation

Documentation of the original hkl_ioc.mac file.

Apply Markup

Tip

We will edit the hkl_ioc.mac file now. Before we start applying markup, it’s a good idea to make a backup copy of the original:

cp hkl_ioc.mac  hkl_ioc.mac.original

Here are the steps to consider when converting SPEC comments to reST markup.

  1. identify the SPEC comments
  2. extended comments (docstrings) #. global docstring #. macro docstring #. others are ignored by Sphinx
  3. descriptive comments

SPEC comments

Obvious as this sounds, it may help someone to see that the SPEC comments are on lines 1-32. It is easy to place this entire block within an extended comment [1] (known hereafter as a docstring). Make these additions to lines 1 and 32:

line new
1 """#===============================================================================
32 #==============================================================================="""

But this is not enough, as the content will look like a wreck.


#=============================================================================== #**************SPEC macros for the Advanced Photon Source*********************** #=============================================================================== # # Beamline/Sector: 4ID # # Macro Package: hkl_ioc.mac # # Version: 1.0 (August,2005) #

... and so forth

So, there is a choice to make. Either:

  1. format the comment as literal text (least work)
  2. reformat the as reST. (more work, looks better)

Literal text

To format a SPEC comment as literal text, consider this brief SPEC comment:

1
2
3
# Summary: This macro scans the sample in a circular mesh.
#
# Dependencies: It is part of the circular mesh macro package.

Its literal text rendition in reST is written:

1
2
3
4
5
6
7
8
"""
::

        # Summary: This macro scans the sample in a circular mesh.
        #
        # Dependencies: It is part of the circular mesh macro package.

"""

which looks like:


# Summary: This macro scans the sample in a circular mesh.
#
# Dependencies: It is part of the circular mesh macro package.

Note that the two colons indicate literal text follows. Both the blank line after the colons and the final blank line are required to avoid warnings. And, the entire comment must be indented at least one column to the right of the two colons.

reST markup

In reST, the SPEC comment above might be written as two definition list items [2]:

1
2
3
4
5
6
7
8
"""
Summary
    This macro scans the sample in a circular mesh.

Dependencies
    It is part of the circular mesh macro package.

"""

which looks like:


Summary
This macro scans the sample in a circular mesh.
Dependencies
It is part of the circular mesh macro package.

(The final blank line is necessary to avoid warnings.)

This markup does not look too complicated until we reach the Modification history starting at line 23. The content here might be coded as either literal text (above) or a reST table. Since the table is easy and CVS is no longer used to build the revision history, we’ll format it as a table.

Consider this SPEC comment:

1
2
3
4
5
#Revision 1.3  2006/05/22 20:34:35  jiaox
#removed unsed lines in ioc_HKL.
#
#Revision 1.2  2006/05/11 17:46:31  jiaox
#Added CVS Log entry.

It might be put into a table [3] such as:

1
2
3
4
5
6
========   ===================  =======  =====================================
Revision   date/time            author   remarks
========   ===================  =======  =====================================
1.3        2006/05/22 20:34:35  jiaox    removed unsed lines in ioc_HKL.
1.2        2006/05/11 17:46:31  jiaox    Added CVS Log entry.
========   ===================  =======  =====================================

which looks like:


Revision date/time author remarks
1.3 2006/05/22 20:34:35 jiaox removed unsed lines in ioc_HKL.
1.2 2006/05/11 17:46:31 jiaox Added CVS Log entry.

Global Docstring

The convention is to treat the first docstring in a macro file as the global docstring.

With these ideas in mind, here is the markup of the first 32 lines:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
"""
SPEC macros for the Advanced Photon Source

Beamline/Sector
        4ID

Macro Package
        hkl_ioc.mac

Version
        1.0 (August,2005)

Description
        A user defined calcHKL to write the current HKL postion to a
        soft IOC. It requires spec softioc running.

Written by
        X. Jiao 08/08/2005

Modified by:

User macros
        ioc_HKL -> to turn on/off the feature of putting HKL to shared
        memory.

Internal macros
        ioc_put_HKL -> write HKL to the soft IOC

Modification history:

========   ===================  =======  =====================================
Revision   date/time            author   remarks
========   ===================  =======  =====================================
1.3        2006/05/22 20:34:35  jiaox    removed unsed lines in ioc_HKL.
1.2        2006/05/11 17:46:31  jiaox    Added CVS Log entry.
========   ===================  =======  =====================================
"""

which (except for the section title which is hard to render in this document) looks like:


Beamline/Sector
4ID
Macro Package
hkl_ioc.mac
Version
1.0 (August,2005)
Description
A user defined calcHKL to write the current HKL postion to a soft IOC. It requires spec softioc running.
Written by
  1. Jiao 08/08/2005

Modified by:

User macros
ioc_HKL -> to turn on/off the feature of putting HKL to shared memory.
Internal macros
ioc_put_HKL -> write HKL to the soft IOC

Modification history:

Revision date/time author remarks
1.3 2006/05/22 20:34:35 jiaox removed unsed lines in ioc_HKL.
1.2 2006/05/11 17:46:31 jiaox Added CVS Log entry.

Test

Be sure to test your changes as you progress, until you are confident with reST markup. The make process is efficient, only rebuilding the documentation from affected .rst souce file changes. Usually, this also considers changes in the .mac files. This command is usually all it takes to rebuild the HTML documentation:

make html

However, you might wish to make sure changes in the .mac files cause documentation to be rebuilt. It might be easier, although less efficient, to rebuild your HTML documentation each time using this command:

make clean html

The builds are usually very fast (seconds).

Docstring markup in each macro definition

Each of the macro definitions can be marked up to provide documentation with the definition. The convention is to supply a short one-line summary first, then additional information as appropriate.

Consider the definition for ioc_HKL. A summary of it is given in the first comment section. We’ll apply that as the docstring:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def ioc_HKL '{
    """to turn on/off the feature of putting HKL to shared memory."""

    if($# != 1) { eprint "Usage: ioc_HKL on/off ";exit}


    if(("$1" == "on")) {
       cdef("user_save_HKL","ioc_put_HKL","ioc_HKL","0x20")
       print "Now put HKL to softioc."
       exit
    }
    if(("$1" == "off")) {
       cdef("user_save_HKL","","ioc_HKL","delete")
       print "Stop put HKL to softioc."
       exit
    }
    eprint "Usage: ioc_HKL on/off "
}'

Do the same thing for the ioc_put_HKL macro definition.

Document the global variable

On line 45 (in the original file), there is a global variable declaration: global SIOC_PV. The description for this variable has been deduced from its usage in this file with EPICS. [4] It is possible to document SIOC_PV using a Descriptive comments. Insert the line containing global SIOC_PV with this one:

global SIOC_PV             ;#: soft IOC PV name

The semicolon is used to ensure that the spec command is finished. It might be unnecessary. The descriptive comment can be used in-line to define the item on that line.

Similarly, add another Descriptive comments to document line 38 (original file) by inserting this line before the line that reads cdef("user_save_HKL","","ioc_HKL"):

#: preload check/setting here

Here the descriptive comment appearing on one line will provide a summary for the item defined on the next line only.

Final Results

Rebuild the completed ../markup_example/hkl_ioc.mac documentation with:

make html

Note

Don’t be concerned about the warnings of SEVERE: Duplicate ID: "cdef-user_save_HKL". These messages are only informative. This bug should be resolved in a future version of specdomain.

After refreshing the page in the WWW browser, it should like this:

view of marked-up hkl_ioc.mac HTML documentation

Documentation of the marked-up hkl_ioc.mac file.

and the index will look like:

index of marked-up hkl_ioc.mac HTML documentation

Index of the marked-up hkl_ioc.mac file.

Note

It is planned for the future to provide options for sorting the output alphabetically and to provide other features.


Footnotes

[1]

a SPEC extended comment is text that is surrounded by three double-quote characters ("""), such as:

“”“this triple-quoted text is a docstring”“”

In the Python language, this is known as a docstring. But, unlike Python, SPEC does not recognize single quotes to mark extended comments. Only use the double quote character.

[2]definition list: http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#definition-lists
[3]table: http://sphinx.pocoo.org/rest.html#tables
[4]EPICS: http://www.aps.anl.gov/epics