diff --git a/actions/doc/index_dev.rst b/actions/doc/index_dev.rst
index a02d37689e27504f350f51fcf148dfeeab5ccfee..8594a9dd4480a51680093fbc15db84995fc9d2ef 100644
--- a/actions/doc/index_dev.rst
+++ b/actions/doc/index_dev.rst
@@ -1,6 +1,10 @@
:mod:`test_actions.ActionTestCase` - Testing Actions
================================================================================
+.. module:: test_actions
+
+.. currentmodule:: test_actions
+
This module is **not** part of the |project| binary distribution. That is the
productive bit running to produce models. It is only part of the source
distribution intended to help developing |project|. Basically it supports you
diff --git a/doc/conf.py.in b/doc/conf.py.in
index 6763c6cedfec2d54c7a22527511815762de560c1..f3bbada79eea0d4943c476d44d5e8f6e42a51ca2 100644
--- a/doc/conf.py.in
+++ b/doc/conf.py.in
@@ -268,7 +268,8 @@ extlinks = {'py_docs' : ('@PYTHON_DOC_URL@/%s',
'OpenStructure documentation')}
# The _nameattr is a bit ugly: we want to have __name__ formatted as Python
# attribute but Sphinx does not go with calling :attr: inside extlinks. To keep
-# the Python url prefix, we define sth here.
+# the Python url prefix, we define sth here. Same holds for _mainattr. But this
+# time instead of printing '__name__' we want to see '__main__'.
rst_epilog = """
.. |project| replace:: %s
.. |cmake| replace:: CMake
@@ -284,6 +285,7 @@ rst_epilog = """
.. |C++| replace:: C++
.. _ost_s: http://www.OpenStructure.org
.. _nameattr: @PYTHON_DOC_URL@/library/__main__.html
+.. _mainattr: @PYTHON_DOC_URL@/library/__main__.html
.. |pep8| replace:: PEP 8
.. _pep8: https://www.python.org/dev/peps/pep-0008/
""" % project
diff --git a/doc/contributing.rst b/doc/contributing.rst
index acb3b011e34c58983a1ff19cb5b928f60cb73839..c898ea72fe89180048d3e09a1e4ced7b5f9e09bb 100644
--- a/doc/contributing.rst
+++ b/doc/contributing.rst
@@ -270,6 +270,8 @@ http://sphinx-doc.org/markup/inline.html
If you write new functionality for |project|, or fix bugs, feel free to extend
the Changelog. It will be automatically pulled into the documentation.
+.. _how-to-start-your-own-module:
+
--------------------------------------------------------------------------------
How To Start Your Own Module
--------------------------------------------------------------------------------
@@ -640,6 +642,142 @@ you.
Now tests should be available by ``make check``, ``make codetest`` and
``make test_something.py_run``.
+--------------------------------------------------------------------------------
+How To Start Your Own Action
+--------------------------------------------------------------------------------
+In |project| we call scripts/ programs 'actions'. They are started by a
+launcher found in your staging directory at :file:`stage/bin/pm`. This little
+guy helps keeping the shell environment in the right mood to carry out your
+job. So usually you will start an action by
+
+.. code-block:: console
+
+ $ stage/bin/pm help
+
+To start your own action, follow :ref:`how-to-start-your-own-module` until
+creating a directory structure for a new module. Also **do** go for a dedicated
+branch for action-development. There you can produce intermediate commits while
+other branches stay clean in case you have to do some work there which needs to
+get public.
+
+After preparing your repository its time to create a file for the action. That
+is a bit different than for modules. Assuming we are sitting in the
+repository's root:
+
+.. code-block:: console
+
+ $ touch action/pm-awesome-action
+ $ chmod +x action/pm-awesome-action
+
+Two things are important here: actions are prefixed with :file:`pm-`, so they
+are recognised by the :file:`pm` launcher. Secondly, action files need to be
+executable, which does not propagate if you do it **after** the first call to
+``make``.
+
+To get the new action recognised by ``make`` to be placed in
+:file:`stage/libexec/promod3`, it has to be registered with |cmake| in
+:file:`actions/CMakeLists.txt`:
+
+.. code-block:: cmake
+ :linenos:
+
+ add_custom_target(actions ALL)
+ add_subdirectory(tests)
+
+ pm_action_init()
+ pm_action(pm-build-rawmodel actions)
+ pm_action(pm-help actions)
+ pm_action(pm-awesome-action actions)
+
+Just add your action with its full filename with a call to
+:cmake:command:`pm_action` at the end of the file.
+
+Before coding your action, lets set up unit tests for it. Usually when adding
+features, you will immediately try them, check that everything works as
+intended, etc.. |project| helps you automatising those tests so its rather easy
+to check later, if code changes break anything. Start with a file
+:file:`actions/tests/test_action_awesome.py`:
+
+.. testcode:: contribute_action
+ :hide:
+
+ import sys
+ sys.dont_write_bytecode = True
+
+ import test_actions
+ import unittest
+
+ class DoAwesomeActionTests(test_actions.ActionTestCase):
+ def __init__(self, *args, **kwargs):
+ test_actions.ActionTestCase.__init__(self, *args, **kwargs)
+ self.pm_bin = os.path.join(os.getcwd(), os.pardir, 'stage', 'bin',
+ 'pm')
+ self.pm_action = 'help'
+
+ def testExit0(self):
+ self.RunExitStatusTest(0, list())
+
+ if __name__ == "__builtin__":
+ import os
+ suite = unittest.TestLoader().loadTestsFromTestCase(DoAwesomeActionTests)
+ unittest.TextTestRunner().run(suite)
+
+.. code-block:: python
+ :linenos:
+
+ import sys
+
+ # this is needed so there will be no test_actions.pyc created in the source
+ # directory
+ sys.dont_write_bytecode = True
+
+ import test_actions
+
+ class AwesomeActionTests(test_actions.ActionTestCase):
+ def __init__(self, *args, **kwargs):
+ test_actions.ActionTestCase.__init__(self, *args, **kwargs)
+ self.pm_action = 'awesome'
+
+ def testExit0(self):
+ self.RunExitStatusTest(0, list())
+
+ if __name__ == "__main__":
+ from ost import testutils
+ testutils.RunTests()
+
+Please note that for actions we are using
+:class:`test_actions.ActionTestCase <test_actions>` instead of
+:class:`unittest.TestCase`. Since testing has a lot in common for different
+actions, we decided to put up a little wrapper around this subject. See the
+documentation of :class:`ActionTestCase <test_actions>` for more information.
+
+Now its time to fill your action with code. Instead of reading a lot more of
+explanations, it should be easy to go by examples from the :file:`actions`
+directory. There are only two really important points:
+
+* No shebang line (``#! /usr/bin/python``) in your action! Also no
+ ``#! /usr/bin/env python`` or anything like this. This may lead to funny side
+ effects, like calling a |python| interpreter from outside a virtual
+ environment or a different version |ost_s|. Basically it may mess up the
+ environment your action is running in. Actions are called by :file:`pm`,
+ that's enough to get everything just right.
+
+* The action of your action happens in the |mainattr|_ branch of the script.
+ Your action will have own function definitions, variables and all the bells
+ and whistles. Hiding behind |mainattr|_ keeps everything separated and makes
+ things easier when it gets to debugging. So just after
+
+ .. code-block:: python
+
+ import alot
+
+ def functions_specific_to_your_action(...):
+
+ if __name__ == "__main__":
+ <put together what your action should do here>
+
+ start putting your action together.
+
--------------------------------------------------------------------------------
Third Party Contributions (License Issues)
--------------------------------------------------------------------------------
@@ -674,6 +812,7 @@ contributions to web pages using |project|.
.. |fedora| replace:: Fedora
.. |nameattr| replace:: :attr:`__name__`
+.. |mainattr| replace:: :attr:`__main__`
.. |pylint| replace:: Pylint
.. _pylint: http://www.pylint.org
.. LocalWords: cmake hotfix doctest linkcheck rebase BRANCHNAME rebasing py
@@ -684,6 +823,8 @@ contributions to web pages using |project|.
.. LocalWords: changelog Optimized DOPTIMIZE gitignore cd conf subtree attr
.. LocalWords: unittest TestCase nameattr testcode staticmethod builtin cp
.. LocalWords: SomethingTests testFileExistsFalse testutils RunTests DQMEAN
-.. LocalWords: pre API inline CMake hh ProMod Bienchen OST OPENSTRUCTURE
+.. LocalWords: pre API inline CMake hh ProMod Bienchen OST OPENSTRUCTURE os
.. LocalWords: mol alg conop QMEAN KIC eigen eigenvectors Lapack rawmodel
-.. LocalWords: OpenStructure ost pylint
+.. LocalWords: OpenStructure ost pylint chmod sys pyc dont bytecode args
+.. LocalWords: AwesomeActionTests ActionTestCase kwargs testExit getcwd
+.. LocalWords: RunExitStatusTest DoAwesomeActionTests pardir mainattr alot