DevAssistant Core

Note: So far, this only covers some bits and pieces of the whole core.

DevAssistant Load Paths

DevAssistant has couple of load path entries, that are searched for assistants, snippets, icons and files used by assistants. In standard installations, there are three paths:

  1. “system” path, which is defined by OS distribution (usually /usr/share/devassistant/) or by Python installation (sth. like /usr/share/pythonX.Y/devassistant/data/)
  2. “local” path, /usr/local/share/devassistant/
  3. “user” path, ~/.devassistant/

Another path(s) can be added by specifying DEVASSISTANT_PATHS environment variable (if more paths are used, they must be separated by colon). These paths are prepended to the list of standard load paths.

Each load path entry has this structure:


Icons under icons directory and files in files directory “copy” must the structure of assistants directory. E.g. for assistant assistants/crt/foo/bar.yaml, the icon must be icons/crt/foo/bar.svg and files must be placed under files/crt/foo/bar/

Assistants Loading Mechanism

DevAssistant loads assistants from all load paths mentioned above (more specifically from <load_path>/assistants/ only), traversing them in order “system”, “local”, “user”.

When DevAssistant starts up, it loads all assistants from all these paths. It assumes, that Creator assistants are located under crt subdirectories the same applies to Modifier (mod), Preparer (prep) and Task (task) assistants.

For example, loading process for Creator assistants looks like this:

  1. Load all assistants located in crt subdirectories of each <load path>/assistants/ (do not descend into subdirectories). If there are multiple assistants with the same name in different load paths, the first traversed wins.
  2. For each assistant named foo.yaml:
    1. If crt/foo directory doesn’t exist in any load path entry, then this assistant is “leaf” and therefore can be directly used by users.
    2. Else this assistant is not leaf and DevAssistant loads its subassistants from the directory, recursively going from point 1).

Command Runners

Command runners... well, they run commands. They are the functionality that makes DevAssistant powerful, since they effectively allow you to create callbacks to Python, where you can cope with the hard parts unsuitable for Yaml assistants.

When DevAssistant executes a run section, it reads commands one by one and dispatches them to their respective command runners. Every command runner can do whatever it wants - for example, we have a command runner that creates Github repos.

After a command runner is run, DevAssistant sets LAST_LRES and LAST_RES global variables for usage (these are rewritten with every command run). These variables represent the logical result of the command (True/False) and result (a “return value”, something computed), much like with Expressions.

For reference of current commands, see Command Reference.

If you’re missing some cool functionality, you can implement your own command runner and send us a pull request. (We’re thinking of creating some sort of import hook that would allow assistants to import command runners from Python files outside of DevAssistant, but it’s not on the priority list right now.) Each command must be a class with two classmethods:

class MyCommandRunner(CommandRunner):
    def matches(cls, c):
        return c.comm_type == 'mycomm'

    def run(cls, c):
        formatted = c.format_str()'MyCommandRunner was invoked: {ct}: {ci}'.format(ct=c.comm_type,
        return [True, len(formatted)]

This command runner will run all commands with command type mycomm. For example if your assistant contains:

- $foo: $(echo "using DevAssistant")
- mycomm: You are $foo!

than DevAssistant will print out something like:

INFO: MyCommandRunner was invoked: mycomm: You are using DevAssistant!

After this command is run, LAST_LRES will be set to True and LAST_RES to length of the printed string.

Generally, the matches method should just decide (True/False) whether given command is runnable or not and the run method should actually run it. The run method should use devassistant.logger.logger object to log any messages and it can also raise any exception that’s subclass of devassistant.exceptions.ExecutionException.

The c argument of both methods is a devassistant.command.Command object. You can access the command type via c.comm_type and raw command input via c.comm. If you want to get input as a formatted string, where variables are substituted for their values, use c.format_str(). You can also access (and change - use this wisely!) the global mapping of variables via c.kwargs.

Read the Docs v: v0.8.0
On Read the Docs
Project Home

Free document hosting provided by Read the Docs.