Skip to content
This repository has been archived by the owner on Nov 10, 2018. It is now read-only.

Commit

Permalink
Merge pull request #23 from escapewindow/master
Browse files Browse the repository at this point in the history
Script docs and doc links
  • Loading branch information
escapewindow committed Jun 21, 2015
2 parents d71626b + e76ba59 commit 632f255
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 61 deletions.
1 change: 1 addition & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Linux and OS X
# You can run |tox -e ENV| to run a specific env, e.g. |tox -e py27|
pip install tox
tox
# alternately, ./run_tests.sh


Windows
Expand Down
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Linux and OS X
# You can run |tox -e ENV| to run a specific env, e.g. |tox -e py27|
pip install tox
tox
# alternately, ./run_tests.sh

Windows
-------
Expand Down
1 change: 1 addition & 0 deletions docs/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Linux and OS X
# You can run |tox -e ENV| to run a specific env, e.g. |tox -e py27|
pip install tox
tox
# alternately, ./run_tests.sh

Windows
-------
Expand Down
1 change: 1 addition & 0 deletions docs/README.rst.j2
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Linux and OS X
# You can run |tox -e ENV| to run a specific env, e.g. |tox -e py27|
pip install tox
tox
# alternately, ./run_tests.sh

Windows
-------
Expand Down
43 changes: 23 additions & 20 deletions docs/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ Commands
Command and run()
#################

The ``Command`` object simply takes an external command and runs it, logging stdout and stderr as each message arrives. The main benefits of using ``Command`` are logging and timeouts. ``Command`` takes two timeouts: ``output_timeout``, which is how long the command can go without outputting anything before timing out, and ``max_timeout``, which is the total amount of time that can elapse from the start of the command.
The Command_ object simply takes an external command and runs it, logging stdout and stderr as each message arrives. The main benefits of using Command_ are logging and timeouts. Command_ takes two timeouts: ``output_timeout``, which is how long the command can go without outputting anything before timing out, and ``max_timeout``, which is the total amount of time that can elapse from the start of the command.

(The command is run via ``subprocess.Popen`` and timeouts are monitored via the `multiprocessing` module.)

After the command is run, it runs the ``detect_error_cb`` callback function to determine whether the command was run successfully.

The process of creating and running a ``Command`` is twofold: ``Command.__init__`` and ``Command.run()``. As a shortcut, there is a run_ function that will do both steps for you.

.. _run: scriptharness.commands.html#scriptharness.commands.run
The process of creating and running a Command_ is twofold: `Command.__init__()`_ and `Command.run()`_. As a shortcut, there is a `run()`_ function that will do both steps for you.


.. _ParsedCommand-and-parse:
Expand All @@ -26,11 +24,9 @@ ParsedCommand and parse()

Ideally, external command output would be for humans only, and the exit code would be meaningful. In practice, this is not always the case. Exit codes aren't always helpful or even meaningful, and sometimes critical information is buried in a flood of output.

``ParsedCommand`` takes the output of a command and parses it for matching substrings or regular expressions, using :ref:`ErrorLists-and-OutputParser` to determine the log level of a line of output. Because it subclasses ``Command``, ``ParsedCommand`` also has built-in ``output_timeout`` and ``max_timeout`` support.

As with ``Command`` and ``run()``, ``ParsedCommand`` has a shortcut function, parse_.
ParsedCommand_ takes the output of a command and parses it for matching substrings or regular expressions, using :ref:`ErrorLists-and-OutputParser` to determine the log level of a line of output. Because it subclasses Command_, ParsedCommand_ also has built-in ``output_timeout`` and ``max_timeout`` support.

.. _parse: scriptharness.commands.html#scriptharness.commands.parse
As with Command_ and `run()`_, ParsedCommand_ has a shortcut function, `parse()`_.


.. _ErrorLists-and-OutputParser:
Expand All @@ -41,8 +37,6 @@ ErrorLists and OutputParser

The ErrorList_ object describes which lines of output are of special interest. It's a class for better validation.

.. _ErrorList: scriptharness.errorlists.html#scriptharness.errorlists.ErrorList

An example error_list::

[
Expand All @@ -66,9 +60,8 @@ Any output line that matches the first regex will be ignored (discarded), becaus

The final substring has an explanation that will be logged immediately after the matching line, to explain vague error messages. Because it has a defined `exception`, it will raise.

``ParsedCommand`` sends its output to the OutputParser_ object, which passes it on to the ``ErrorList``. It keeps track of the number of errors and warnings, as well as handling any context line buffering through the ``OutputBuffer``.
ParsedCommand_ sends its output to the OutputParser_ object, which passes it on to the ErrorList_. It keeps track of the number of errors and warnings, as well as handling any context line buffering through the OutputBuffer_.

.. _OutputParser: scriptharness.log.html#scriptharness.log.OutputParser


.. _OutputBuffer-and-context-lines:
Expand All @@ -90,8 +83,6 @@ The OutputBuffer_ holds the buffered output for ``pre_context_lines``, and keeps

If multiple lines match, and a line of output is marked as multiple levels, the highest level will win. E.g., ``logging.CRITICAL`` will beat ``logging.ERROR``, which will beat ``logging.WARNING``, etc.

.. _OutputBuffer: scriptharness.log.html#scriptharness.log.OutputBuffer


.. _Output-get_output-and-get_text_output:

Expand All @@ -101,11 +92,23 @@ Output, get_output(), and get_text_output()

Sometimes you need to manipulate the output from a command, not just log it or perform general error parsing. There's ``subprocess.check_output()``, but that doesn't log or have full timeout support.

Enter Output_. This also inherits ``Command``, but because ``Output.run`` is a completely different method than ``Command.run``, it has its own timeout implementation. (It does still support both ``output_timeout`` and ``max_timeout``.) It redirects STDOUT and STDERR to temp files.
Enter Output_. This also inherits Command_, but because `Output.run()`_ is a completely different method than `Command.run()`_, it has its own timeout implementation. (It does still support both ``output_timeout`` and ``max_timeout``.) It redirects STDOUT and STDERR to temp files.

.. _Output: scriptharness.commands.html#scriptharness.commands.Output

Much like ``Command`` has its helper ``run`` function, ``Output`` has `two` helper functions: get_output_ and get_text_output_. The former yields the ``Output`` object, and the caller can either access the ``NamedTemporaryFile`` ``Output.stdout`` and ``Output.stderr`` objects, or use the ``Output.get_output()`` method. Because of this, it is suitable for binary or lengthy output. ``get_text_output()`` will get the STDOUT contents for you, log them, and return them to you.
Much like Command_ has its helper `run()`_ function, Output_ has `two` helper functions: `get_output()`_ and `get_text_output()`_. The former yields the Output_ object, and the caller can either access the ``NamedTemporaryFile`` Output.stdout_ and Output.stderr_ objects, or use the `Output.get_output()`_ method. Because of this, it is suitable for binary or lengthy output. `get_text_output()`_ will get the STDOUT contents for you, log them, and return them to you.

.. _get_output: scriptharness.commands.html#scriptharness.commands.get_output
.. _get_text_output: scriptharness.commands.html#scriptharness.commands.get_text_output
.. _Command: scriptharness.commands.html#scriptharness.commands.Command
.. _Command.__init__(): scriptharness.commands.html#scriptharness.commands.Command.__init__
.. _Command.run(): scriptharness.commands.html#scriptharness.commands.Command.run
.. _ErrorList: scriptharness.errorlists.html#scriptharness.errorlists.ErrorList
.. _Output: scriptharness.commands.html#scriptharness.commands.Output
.. _Output.get_output(): scriptharness.commands.html#scriptharness.commands.Output.get_output
.. _Output.run(): scriptharness.commands.html#scriptharness.commands.Output.run
.. _Output.stdout: scriptharness.commands.html#scriptharness.commands.Output.stdout
.. _Output.stderr: scriptharness.commands.html#scriptharness.commands.Output.stderr
.. _OutputBuffer: scriptharness.log.html#scriptharness.log.OutputBuffer
.. _OutputParser: scriptharness.log.html#scriptharness.log.OutputParser
.. _ParsedCommand: scriptharness.commands.html#scriptharness.commands.ParsedCommand
.. _get_output(): scriptharness.commands.html#scriptharness.commands.get_output
.. _get_text_output(): scriptharness.commands.html#scriptharness.commands.get_text_output
.. _parse(): scriptharness.commands.html#scriptharness.commands.parse
.. _run(): scriptharness.commands.html#scriptharness.commands.run
58 changes: 28 additions & 30 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ Configuration
Configuration Overview
######################

The runtime configuration of a Script is built from several layers.
The runtime configuration of a Script_ is built from several layers.

* There is a ``ConfigTemplate`` that can have default values for certain config variables. These defaults are the basis of the config dict. (See :ref:`Config-Templates` for more details on ``ConfigTemplates``).
* There is a ConfigTemplate_ that can have default values for certain config variables. These defaults are the basis of the config dict. (See :ref:`Config-Templates` for more details on ConfigTemplate_).

* The script can define an ``initial_config`` dict that is laid on top of the ``ConfigTemplate`` defaults, so any shared config variables are overwritten by the ``initial_config``.
* The script can define an ``initial_config`` dict that is laid on top of the ConfigTemplate_ defaults, so any shared config variables are overwritten by the ``initial_config``.

* The ``ConfigTemplate`` has a ``get_parser()`` method that generates an ``argparse.ArgumentParser``. This parser parses the commandline options.
* The `ConfigTemplate.get_parser()`_ method generates an ``argparse.ArgumentParser``. This parser parses the commandline options.

* If the commandline options specify any files via the ``--config-file`` option, then those files are read, and the contents are overlaid on top of the config. The first file specified will be overlaid first, then the second, and so on.

Expand All @@ -30,30 +30,30 @@ ConfigTemplates

It's very powerful to be able to build a configuration dict that can hold any key value pairs, but it's non-trivial for users to verify if their config is valid or if there are options that they're not taking advantage of.

To make the config more well-defined, we have the ``ConfigTemplate``. The ``ConfigTemplate`` is comprised of ``ConfigVariables``, and is based on the ``argparse.ArgumentParser``, but with these qualities:
To make the config more well-defined, we have the ConfigTemplate_. The ConfigTemplate_ is comprised of ConfigVariable_ objects, and is based on the ``argparse.ArgumentParser``, but with these qualities:

* The ``ConfigTemplate`` can keep track of all config variables, including ones that aren't available as commandline options. The option-less config variables must be specified via default, config file, or ``initial_config``.
* The ConfigTemplate_ can keep track of all config variables, including ones that aren't available as commandline options. The option-less config variables must be specified via default, config file, or ``initial_config``.

* The templates can be added together, via ``ConfigTemplate.update()``.
* The templates can be added together, via `ConfigTemplate.update()`_.

* Each ``ConfigVariable`` self-validates, and the ``ConfigTemplate`` makes sure there are no conflicting commandline options.
* Each ConfigVariable_ self-validates, and the ConfigTemplate_ makes sure there are no conflicting commandline options.

* There is a ``ConfigTemplate.remove_option()`` method to remove a commandline option from the corresponding ``ConfigVariable``. This may be needed if you want to add two config templates together, but they both have a ``-f`` commandline option specified, for example.
* There is a `ConfigTemplate.remove_option()`_ method to remove a commandline option from the corresponding ConfigVariable_. This may be needed if you want to add two config templates together, but they both have a ``-f`` commandline option specified, for example.

* The ``ConfigTemplate.validate_config()`` method validates the built configuration. Each ``ConfigVariable`` can define whether they're required, whether they require or are incompatible with other variables (``required_vars`` and ``incompatible_vars``), and each can define their own ``validate_cb`` callback function.
* The `ConfigTemplate.validate_config()`_ method validates the built configuration. Each ConfigVariable_ can define whether they're required, whether they require or are incompatible with other variables (``required_vars`` and ``incompatible_vars``), and each can define their own ``validate_cb`` callback function.

* There is a ``ConfigTemplate.add_argument()`` for those who want to maintain argparse syntax.
* There is a `ConfigTemplate.add_argument()`_ for those who want to maintain argparse syntax.

Parent parsers are supported, to group commandline options in the ``--help`` output. Subparsers are not currently supported, though it may be possible to replace the ``ConfigTemplate.parser`` with a subparser-enabled parser at the expense of validation and the ability to ``ConfigTemplate.update()``.
Parent parsers are supported, to group commandline options in the ``--help`` output. Subparsers are not currently supported, though it may be possible to replace the ConfigTemplate.parser_ with a subparser-enabled parser at the expense of validation and the ability to `ConfigTemplate.update()`_.

When supporting downstream scripts, it's best to keep each ``ConfigTemplate`` modular. It's easy to combine them via ``ConfigTemplate.update()``, but less trivial to remove functionality. The action config template, for instance, can be added to the base config template right before running ``parse_args()``.
When supporting downstream scripts, it's best to keep each ConfigTemplate_ modular. It's easy to combine them via `ConfigTemplate.update()`_, but less trivial to remove functionality. The action config template, for instance, can be added to the base config template right before running `parse_args()`_.


############################
LoggingDict and ReadOnlyDict
############################

Each Script has a config dict. By default, this dict is a ``LoggingDict``, which logs any changes made to the config.
Each Script_ has a config dict. By default, this dict is a LoggingDict_, which logs any changes made to the config.

For example, if the config looked like::

Expand All @@ -71,23 +71,21 @@ then updating the config might log::

00:11:22 INFO - root.config['baz'] update: y now 8

Alternatively, someone could change the script class to ``StrictScript``, which uses ``ReadOnlyDict``. Once the ``ReadOnlyDict`` is locked, it cannot be modified.
Alternatively, someone could change the script class to StrictScript_, which uses ReadOnlyDict_. Once the ReadOnlyDict_ is locked, it cannot be modified.

By either explicitly logging any changes to the config, and/or preventing any changes to the config, it's easier to debug any unexpected behavior.


.. _Contexts:

########
Contexts
########

As each Action is run, it passes a ``Context`` to the action function. The ``Context`` is a ``namedtuple`` with the following properties:

* script (Script object): the Script calling the Action
* config (dict): by default this is a ``LoggingDict``
* logger (logging.Logger): the logger for the Script
* action (Action object): this is only defined during the ``RUN_ACTION``, ``PRE_ACTION``, and ``POST_ACTION`` phases.
* phase (str): this will be one of ``PRE_RUN``, ``POST_RUN``, ``PRE_ACTION``, ``POST_ACTION``, or ``POST_FATAL``, depending on which phase we're in.

The logger and config (and to a lesser degree, the script and action) objects are all available to each function called for convenience and consistency.
.. _ConfigTemplate: scriptharness.config.html#scriptharness.config.ConfigTemplate
.. _ConfigTemplate.add_argument(): scriptharness.config.html#scriptharness.config.ConfigTemplate.add_argument
.. _ConfigTemplate.get_parser(): scriptharness.config.html#scriptharness.config.ConfigTemplate.get_parser
.. _ConfigTemplate.parser: scriptharness.config.html#scriptharness.config.ConfigTemplate.parser
.. _ConfigTemplate.remove_option(): scriptharness.config.html#scriptharness.config.ConfigTemplate.remove_option
.. _ConfigTemplate.update(): scriptharness.config.html#scriptharness.config.ConfigTemplate.update
.. _ConfigTemplate.validate_config(): scriptharness.config.html#scriptharness.config.ConfigTemplate.validate_config
.. _ConfigVariable: scriptharness.config.html#scriptharness.config.ConfigVariable
.. _LoggingDict: scriptharness.structures.html#scriptharness.structures.LoggingDict
.. _ReadOnlyDict: scriptharness.structures.html#scriptharness.structures.ReadOnlyDict
.. _Script: scriptharness.script.html#scriptharness.script.Script
.. _StrictScript: scriptharness.script.html#scriptharness.script.StrictScript
.. _parse_args(): scriptharness.config.html#scriptharness.config.parse_args
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
quickstart
enabling_actions
config
script
commands
scriptharness
releasenotes
Expand Down
17 changes: 9 additions & 8 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
Quickstart
==========

Here's an example script. The file is also viewable here_.

.. _here: https://github.com/scriptharness/python-scriptharness/blob/master/examples/quickstart.py
Here's an example script, quickstart.py_.

::

Expand Down Expand Up @@ -241,31 +239,34 @@ see what the config is without running anything, you can use the
You can always use the ``--help`` option::

$ ./quickstart.py --help
usage: quickstart.py [-h] [--config-file CONFIG_FILE] [--dump-config]
usage: quickstart.py [-h] [--dump-config] [--config-file CONFIG_FILE]
[--opt-config-file CONFIG_FILE]
[--add-actions ACTION [ACTION ...]]
[--action-group {none,all}] [--list-actions]
[--actions ACTION [ACTION ...]]
[--add-actions ACTION [ACTION ...]]
[--skip-actions ACTION [ACTION ...]]
[--new-argument NEW_ARGUMENT]
optional arguments:
-h, --help show this help message and exit
--dump-config Log the built configuration and exit.
--config-file CONFIG_FILE, --cfg CONFIG_FILE, -c CONFIG_FILE
Specify required config files/urls
--dump-config Log the built configuration and exit.
--opt-config-file CONFIG_FILE, --opt-cfg CONFIG_FILE
Specify optional config files/urls
--add-actions ACTION [ACTION ...]
Specify the actions to add to the default set.
--action-group {none,all}
Specify the action group to use.
--list-actions List all actions (default prepended with '*') and
exit.
--actions ACTION [ACTION ...]
Specify the actions to run.
--add-actions ACTION [ACTION ...]
Specify the actions to add to the default set.
--skip-actions ACTION [ACTION ...]
Specify the actions to skip.
--new-argument NEW_ARGUMENT
help message for --new-argument



.. _quickstart.py: https://github.com/scriptharness/python-scriptharness/blob/master/examples/quickstart.py
6 changes: 3 additions & 3 deletions docs/quickstart.rst.j2
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
Quickstart
==========

Here's an example script. The file is also viewable here_.

.. _here: https://github.com/scriptharness/python-scriptharness/blob/{{git_branch}}/examples/quickstart.py
Here's an example script, quickstart.py_.

::

Expand Down Expand Up @@ -71,3 +69,5 @@ You can always use the ``--help`` option::
$ ./quickstart.py --help
{{help_output}}


.. _quickstart.py: https://github.com/scriptharness/python-scriptharness/blob/{{git_branch}}/examples/quickstart.py
Loading

0 comments on commit 632f255

Please sign in to comment.