diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 6d6bf3e3..7b54c06d 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,4 +1,12 @@ version: 2 +build: + os: "ubuntu-22.04" + tools: + python: "3.11" + +sphinx: + configuration: doc/sphinx/conf.py + fail_on_warning: true python: install: diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py index b18ae387..a9462024 100644 --- a/doc/sphinx/conf.py +++ b/doc/sphinx/conf.py @@ -25,7 +25,7 @@ # 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'] +extensions = ['sphinx.ext.autodoc', 'sphinx_rtd_theme'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -86,20 +86,13 @@ # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] -os_rtd = os.environ.get('READTHEDOCS', None) == 'True' -if os_rtd: - html_theme = 'default' -else: - import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. #html_theme = 'default' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -118,7 +111,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = 'clustershell-nautilus-logo200.png' +html_logo = '_static/clustershell-nautilus-logo200.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 @@ -131,8 +124,9 @@ html_static_path = ['_static'] def setup(app): - # RTD does not line wrap CSV tables, so we override this behavior. - app.add_stylesheet("theme_overrides.css") + if 'READTHEDOCS' in os.environ: + # RTD does not line wrap CSV tables, so we override this behavior. + app.add_stylesheet("theme_overrides.css") # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. diff --git a/lib/ClusterShell/Engine/Engine.py b/lib/ClusterShell/Engine/Engine.py index 0a5b21f9..a3cba2e3 100644 --- a/lib/ClusterShell/Engine/Engine.py +++ b/lib/ClusterShell/Engine/Engine.py @@ -140,7 +140,7 @@ def set_nextfire(self, fire_delay, interval=-1): """ Set the next firing delay in seconds for an EngineTimer object. - The optional parameter `interval' sets the firing interval + The optional parameter *interval* sets the firing interval of the timer. If not specified, the timer fires once and then is automatically invalidated. diff --git a/lib/ClusterShell/MsgTree.py b/lib/ClusterShell/MsgTree.py index 437466b3..a63ee2bc 100644 --- a/lib/ClusterShell/MsgTree.py +++ b/lib/ClusterShell/MsgTree.py @@ -182,7 +182,7 @@ class MsgTree(object): def __init__(self, mode=MODE_DEFER): """MsgTree initializer - The `mode' parameter should be set to one of the following constant: + The *mode* parameter should be set to one of the following constant: MODE_DEFER: all messages are processed immediately, saving memory from duplicate message lines, but keys are associated to tree elements diff --git a/lib/ClusterShell/NodeSet.py b/lib/ClusterShell/NodeSet.py index 18ad449b..70c3b801 100644 --- a/lib/ClusterShell/NodeSet.py +++ b/lib/ClusterShell/NodeSet.py @@ -557,8 +557,8 @@ def clear(self): def __ior__(self, other): """ - Implements the |= operator. So ``s |= t`` returns nodeset s with - elements added from t. (Python version 2.5+ required) + Implements the ``|=`` operator. So ``s |= t`` returns nodeset s + with elements added from t. (Python version 2.5+ required) """ self._binary_sanity_check(other) self.update(other) diff --git a/lib/ClusterShell/NodeUtils.py b/lib/ClusterShell/NodeUtils.py index 82cfa011..926921f2 100644 --- a/lib/ClusterShell/NodeUtils.py +++ b/lib/ClusterShell/NodeUtils.py @@ -96,7 +96,7 @@ def __init__(self, name, groups=None, allgroups=None): :param name: group source name :param groups: group to nodes dict - :param allgroups: optional _all groups_ result (string) + :param allgroups: optional "all groups" result (string) """ self.name = name self.groups = groups or {} # we avoid the use of {} as default argument diff --git a/lib/ClusterShell/Task.py b/lib/ClusterShell/Task.py index 42141692..f220949a 100644 --- a/lib/ClusterShell/Task.py +++ b/lib/ClusterShell/Task.py @@ -144,6 +144,7 @@ class Task(object): the task associated thread): >>> task.resume() + or: >>> task.run() @@ -463,6 +464,7 @@ def set_default(self, default_key, value): using this method and retrieve them with default(). Task default_keys are: + - "stderr": Boolean value indicating whether to enable stdout/stderr separation when using task.shell(), if not specified explicitly (default: False). @@ -478,8 +480,8 @@ def set_default(self, default_key, value): - "worker": Worker-based class used when spawning workers through shell()/run(). - Threading considerations - ======================== + Threading considerations: + Unlike set_info(), when called from the task's thread or not, set_default() immediately updates the underlying dictionary in a thread-safe manner. This method doesn't @@ -517,6 +519,7 @@ def set_info(self, info_key, value): >>> task.set_info('debug', True) Task info_keys are: + - "debug": Boolean value indicating whether to enable library debugging messages (default: False). - "print_debug": Debug messages processing function. This @@ -535,8 +538,8 @@ def set_info(self, info_key, value): - "tree_default:": In tree mode, overrides the key in Defaults (settings normally set in defaults.conf) - Threading considerations - ======================== + Threading considerations: + Unlike set_default(), the underlying info dictionary is only modified from the task's thread. So calling set_info() from another thread leads to queueing the request for late apply @@ -559,6 +562,7 @@ def shell(self, command, **kwargs): The following optional parameters are passed to the underlying local or remote Worker constructor: + - handler: EventHandler instance to notify (on event) -- default is no handler (None) - timeout: command timeout delay expressed in second using a floating @@ -570,16 +574,16 @@ def shell(self, command, **kwargs): - stdin: enable stdin if set to True or prevent its use otherwise -- default is True. - Local usage:: + Local usage: task.shell(command [, key=key] [, handler=handler] - [, timeout=secs] [, autoclose=enable_autoclose] - [, stderr=enable_stderr][, stdin=enable_stdin])) + [, timeout=secs] [, autoclose=enable_autoclose] + [, stderr=enable_stderr][, stdin=enable_stdin])) - Distant usage:: + Distant usage: task.shell(command, nodes=nodeset [, handler=handler] - [, timeout=secs], [, autoclose=enable_autoclose] - [, tree=None|False|True] [, remote=False|True] - [, stderr=enable_stderr][, stdin=enable_stdin])) + [, timeout=secs], [, autoclose=enable_autoclose] + [, tree=None|False|True] [, remote=False|True] + [, stderr=enable_stderr][, stdin=enable_stdin])) Example: @@ -713,21 +717,21 @@ def port(self, handler=None, autoclose=False): def timer(self, fire, handler, interval=-1.0, autoclose=False): """ Create a timer bound to this task that fires at a preset time - in the future by invoking the ev_timer() method of `handler' + in the future by invoking the ev_timer() method of *handler* (provided EventHandler object). Timers can fire either only once or repeatedly at fixed time intervals. Repeating timers can also have their next firing time manually adjusted. - The mandatory parameter `fire' sets the firing delay in seconds. + The mandatory parameter *fire* sets the firing delay in seconds. - The optional parameter `interval' sets the firing interval of + The optional parameter *interval* sets the firing interval of the timer. If not specified, the timer fires once and then is automatically invalidated. Time values are expressed in second using floating point values. Precision is implementation (and system) dependent. - The optional parameter `autoclose', if set to True, creates + The optional parameter *autoclose*, if set to True, creates an "autoclosing" timer: it will be automatically invalidated as soon as all other non-autoclosing task's objects (workers, ports, timers) have finished. Default value is False, which @@ -1208,16 +1212,15 @@ def key_retcode(self, key): def max_retcode(self): """ - Get max return code encountered during last run - or None in the following cases: - - all commands timed out, - - no command-based worker was executed. + Get max return code encountered during last run or None in the + following cases: - How retcodes work - ================= - If the process exits normally, the return code is its exit - status. If the process is terminated by a signal, the return - code is 128 + signal number. + - all commands timed out + - no command-based worker was executed + + How do retcodes work? If the process exits normally, the return + code is its exit status. If the process is terminated by a + signal, the return code is 128 + signal number. """ return self._max_rc @@ -1261,13 +1264,11 @@ def iter_retcodes(self, match_keys=None): Iterate over return codes of command-based workers, returns a tuple (rc, keys). - Optional parameter match_keys add filtering on these keys. + Optional parameter *match_keys* add filtering on these keys. - How retcodes work - ================= - If the process exits normally, the return code is its exit - status. If the process is terminated by a signal, the return - code is 128 + signal number. + How do retcodes work? If the process exits normally, the return + code is its exit status. If the process is terminated by a + signal, the return code is 128 + signal number. """ if match_keys: # Use the items iterator for the underlying dict. diff --git a/lib/ClusterShell/Worker/Exec.py b/lib/ClusterShell/Worker/Exec.py index ef489c9f..27b71c02 100644 --- a/lib/ClusterShell/Worker/Exec.py +++ b/lib/ClusterShell/Worker/Exec.py @@ -72,7 +72,7 @@ class ExecClient(EngineClient): def __init__(self, node, command, worker, stderr, timeout, autoclose=False, rank=None): """ - Create an EngineClient-type instance to locally run `command'. + Create an EngineClient-type instance to locally run *command*. :param node: will be used as key. """ diff --git a/lib/ClusterShell/Worker/Popen.py b/lib/ClusterShell/Worker/Popen.py index bd288ad0..3fec62ba 100644 --- a/lib/ClusterShell/Worker/Popen.py +++ b/lib/ClusterShell/Worker/Popen.py @@ -41,6 +41,7 @@ class PopenClient(StreamClient): def __init__(self, worker, key, stderr, timeout, autoclose): + """PopenClient initializer""" StreamClient.__init__(self, worker, key, stderr, timeout, autoclose) self.popen = None self.rc = None diff --git a/lib/ClusterShell/Worker/Worker.py b/lib/ClusterShell/Worker/Worker.py index 271e42fa..a0c8abf4 100644 --- a/lib/ClusterShell/Worker/Worker.py +++ b/lib/ClusterShell/Worker/Worker.py @@ -206,9 +206,9 @@ def read(self, node=None, sname='stdout'): Return stream read buffer of current worker. Arguments: - node -- node name; can also be set to None for simple worker - having worker.key defined (default is None) - sname -- stream name (default is 'stdout') + :param node: node name, can also be set to None for simple worker + having worker.key defined (default is None) + :param sname: stream name (default is 'stdout') """ self._task_bound_check() return self.task._msg_by_source(self, node, sname) @@ -463,6 +463,7 @@ class StreamWorker(Worker): it does not execute any external commands by itself. Rather, it should be pre-bound to "streams", ie. file(s) or file descriptor(s), using the two following methods: + >>> worker.set_reader('stream1', fd1) >>> worker.set_writer('stream2', fd2) @@ -492,12 +493,12 @@ def set_reader(self, sname, sfile, retain=True, closefd=True): """Add a readable stream to StreamWorker. Arguments: - sname -- the name of the stream (string) - sfile -- the stream file or file descriptor - retain -- whether the stream retains engine client - (default is True) - closefd -- whether to close fd when the stream is closed - (default is True) + :param sname: the name of the stream (string) + :param sfile: the stream file or file descriptor + :param retain: whether the stream retains engine client + (default is True) + :param closefd: whether to close fd when the stream is closed + (default is True) """ if not self.clients[0].registered: self.clients[0].streams.set_reader(sname, sfile, retain, closefd) @@ -508,12 +509,12 @@ def set_writer(self, sname, sfile, retain=True, closefd=True): """Set a writable stream to StreamWorker. Arguments: - sname -- the name of the stream (string) - sfile -- the stream file or file descriptor - retain -- whether the stream retains engine client - (default is True) - closefd -- whether to close fd when the stream is closed - (default is True) + :param sname: the name of the stream (string) + :param sfile: the stream file or file descriptor + :param retain: whether the stream retains engine client + (default is True) + :param closefd: whether to close fd when the stream is closed + (default is True) """ if not self.clients[0].registered: self.clients[0].streams.set_writer(sname, sfile, retain, closefd) @@ -585,9 +586,9 @@ def read(self, node=None, sname='stdout'): Return stream read buffer of current worker. Arguments: - node -- node name; can also be set to None for simple worker - having worker.key defined (default is None) - sname -- stream name (default is 'stdout') + :param node: node name, can also be set to None for simple worker + having worker.key defined (default is None) + :param sname: stream name (default is 'stdout') """ return Worker.read(self, node or self.clients[0].key, sname)