Source code for watch_do.doer_manager

"""The :class:`.DoerManager` class is responsible for orchestrating the doers.

Commands for the different types of doers, for example the :class:`.Shell`
doer, are provided to this class, which are then parsed and converted to their
respective doer instances. The default doer is also taken into account for
commands that don't explicitly specify a doer.

As an example, the following code would parse out the command specified as the
first argument and create a :class:`.Shell` doer from it.

>>> manager = DoerManager(['shell:echo "%f changed!"'], Shell)

In the above case, the ``shell:`` prefix wasn't necessary, as the default doer
(the second argument) was already set to :class:`.Shell`.

All of the doers can be run by calling the :meth:`.run_doers` method.

>>> manager.run_doers('my_file.txt')
"""

from importlib import import_module

from .exceptions import UnknownDoer


[docs]class DoerManager: """This class creates and manages doers. Commands are passed in, which then get parsed and converted to instances of doers. All doers can be run using the :meth:`.run_doers` method with relevant output returned. """ def __init__(self, commands, default_doer): """Initialise the :class:`.DoerManager` and parse all commands. The commands that get passed into this class are parsed (removing their ``doer:`` prefix if required) and have the relevant doer instances created for them. Parameters: commands (list): A list of strings containing the commands to create doers for. Each command (str) in the list of commands should be prefixed with ``doer:``, where 'doer' is the name of the doer (i.e. ``shell``). If the command is not prefixed with ``doer:`` the ``default_doer`` will be used. default_doer (:class:`.Doer`): A reference to a doer class to use as the default doer if one is not explicitly specified using the ``doer:`` prefix. """ self._commands = commands self._default_doer = default_doer self._doers = self._process_commands(self.commands) @property def commands(self): """list: The list of stings that this :class:`.DoerManager` is managing. """ return self._commands @property def default_doer(self): """:class:`.Doer`: The doer that is used if one is explicitly specified in the command. """ return self._default_doer @property def doers(self): """list: The doers that were created as a result of passing the commands. """ return self._doers def _process_commands(self, commands): """Process the `commands` and create `Doer` instances from them. Parameters: commands (list): A list of strings containing the commands to parse. See the :meth:`.__init__` documentation for details on the format of each command. Raises: UnknownDoer: This method will raise an :meth:`.UnknownDoer` if the given doer doesn't exist. Returns: list: A list of doers that were created from the `commands`. """ token = '::' doers = [] for command in commands: if token in command: token_position = command.find(token) # Parse the doer name and command out of the string doer_name = command[:token_position] doer_name = doer_name.title().replace(' ', '') command_part = command[token_position+len(token):] # Dynamically load the doer try: doers_package = import_module('.doers', 'watch_do') doer = getattr(doers_package, doer_name) except AttributeError: raise UnknownDoer(doer_name) # Create the doer and append it to our list doers.append(doer(command_part)) else: # Use the default doer for our command doers.append(self.default_doer(command)) return doers
[docs] def run_doers(self, file_name): """Run each doer in turn and yield its output. Yields: str: A string that contains the combined output of stdout and stderr from the doers. """ for doer in self.doers: yield from doer.run(file_name)