Command line tools for working with yaq traits and protocols.


yaq-traits can be installed via PyPI or conda-forge.

$ pip install yaq-traits

$ conda config --add channels conda-forge
$ conda install yaq-traits


Avro Protocol (AVPR)
The Avro protocol is the fully specified description of the daemon. It describes the exposed method signatures (names, arguments, defaults to arguments, text description). In addition, yaq avpr files include information about the configuration, state, and traits of a daemon. Avpr is a JSON file.
TOML is a configuration file. Here, we use TOML files to specify the minimum info about a daemon. (i.e. behavior and descriptions inherited via traits is not included in the TOML) A full reference is available below.
A trait is simply a collection of exposed methods, configuration, and state used to encourage shared behavior among similar yaq daemons with different implementations


yaq-traits is a command line application.


Help: learn more, right from your terminal.

$ yaq-traits --help
Usage: yaq-traits [OPTIONS] COMMAND [ARGS]...

  --version  Show the version and exit.
  --help     Show this message and exit.


Try yaq-traits --help to learn more about a particular command.


List: list available traits

$ yaq-traits list


Compose: Convert a simplified TOML file to a fully specified AVPR. This takes a path to a TOML file as an argument, and prints the AVPR to standard out.

$ yaq-traits compose my-daemon.toml > my-daemon.avpr


Get: Retrieve a fully specified AVPR for a trait (similar to compose, but not a full daemon). This takes a name of a trait as an argument, and prints the AVPR to standard out.

$ yaq-traits get has-limits > has-limits.avpr


Check: Verify that an AVPR file matches current trait behavior. This takes a path to an AVPR file as an argument, and prints a table of traits and whether the trait was found to be accurate. If it fails, the traits which are not specified are explicitly printed and a nonzero exit status is returned. The primary intent of check is to be used by Continuous Integration tests, which consistently get the latest version and will alert you if there is a change to the traits.

$ yaq-traits check fake-continuous-hardware.avpr
| trait               | expected | measured |
| has-limits          | true     | true     |
| has-position        | true     | true     |
| has-turret          | false    | false    |
| is-daemon           | true     | false    |
| is-discrete         | false    | false    |
| is-homeable         | false    | false    |
| uses-i2c            | false    | false    |
| uses-serial         | false    | false    |
| uses-uart           | false    | false    |
| has-measure-trigger | false    | false    |
| is-sensor           | false    | false    |
Error: failed to verify expected trait(s):

What to do when a check fails:

yaq TOML file specification

In general, the TOML file is used to specify the minimal description of a daemon. Inherited behavior from traits are not included. You may assign or reassign the default value of the default, but should not change the documentation, type, or arguments to a message. The same format is used to specify traits within `yaq-traits`.


These identifying information about the daemon are provided as top level keys.
protocol (string)
The name of the daemon. The equivalent for a trait definition is trait.
doc (string)
A description of the daemon, rendered at the top of its documentation page.
traits ({'items': 'string', 'type': 'array'})
List of traits implemented by the daemon. In trait definitions, the analogous entry is requires, which lists traits that are implied by using that trait. If a traits is implied by other traits (e.g. has-limits requires has-position) the required trait need not be specified. is-daemon must be specified by all daemons.
hardware ({'items': 'string', 'type': 'array'})
A list of supported hardware, formatted as 'make:model'. Supported hardware should also appear in known-hardware. Used only for building documentation.


The links are a map of arbitrary keys to URLs. In general links to documentation, source, and a bugtracker are good to have. Additionally links to the manufacturer/library used are common.

[links]  # all optional, arbitrary keys supported
documentation = "https://yaq.fyi/daemons/example-daemon"
source = "https://git.example.com/example-daemon"
bugtracker = "https://git.example.com/example-daemon/-/issues"


Installation is just like links, except with the specific goal of pointing to installable package references. For python, this likely includes a link to PyPI and/or conda-forge.

[installation]  # all optional, arbitrary keys supported
PyPI = "https://pypi.org/project/yaqd-example"
conda-forge = "https://anaconda.org/conda-forge/yaqd-example"


All valid Avro types are valid for yaq.
In addition, yaq-tratis provides a definition for an N-dimensional homogeneous array, which can be used by putting the string "ndarray" as the type.
Unions of types are specified using TOML arrays.
Since TOML does not include a null value (and null is a valid default value, distinct from not having a default) the string "__null__" is used in place of the null literal. Note that when referring to the type, "null" is used, just as "int" is used to specify the integer type.
Named types (e.g. records and enums) may be defined inline where they are used, but may also be provided as an array of tables:


# You may find inline tables/arrays more readable here
# Note that toml forbids multi-line inline tables (arrays can be multi-line)
fields = [{name="message", "type"="string"}]


Each config parameter is a table with the name of the parameter as the key within the [config] table with the following keys:
type (required)
Avro type definition, commonly a string such as "int" or "ndarray", but may be a table representing collection types or a record or an array representing a union of types.
doc (optional)
A string description of the config parameter
default (optional)
The default value if the config parameter is omitted in the daemon configuration. If no default is given, it is considered required.
A daemon may override the default value defined by a trait (or provide one where none was given). Additionally, rather then overwriting the doc, a key addendum may be added to provide additional context to the variable (e.g. communicating that a parameter is required despite a null default value being defined in the trait).


type = "boolean"
default = false
doc = "An example of a boolean config param"

type = ["null", {type = "array", items = "int"}]
default = "__null__"

# Overriding a config from a trait
default = 57600
addendum = "I want to provide more info about why 57600 is the default"


The state is configured exactly the same as config, except that all state variable must have a default value. The same rules about overriding defaults and addenda apply to state variables.


type = "boolean"
default = true
doc = "An example of a boolean state variable"


Messages are the exposed remote procedure calls over the TCP interface. This follows closely the specification provided by Avro. Note that all errors in the Python implementation are treated as strings, though that may change in the future.
If the request field is omitted, the default is [], i.e. no parameters.
If the response field is omitted, the default is "null".
Messages defined by traits should be omitted, only messages unique to the daemon should be included. Messages should not be overridden, as the behavior being the same to the client program is the intent of the traits system.

request = [{"name"="int_value", "type"="int"}]
doc = "Set an example int value."

response = "int"
doc = "Get the example int value."

yaq AVPR file specification

The AVPR files generated are compliant with the Avro specification, however yaq-traits does add additional information such that the avpr alone can be used to render the documentation.
The AVPR files include the complete list of config and state (including those inherited from traits). The links (including installation links) are also included. Additional keys specifying which trait provided a method or config/state variable are also added by yaq-traits

CC0: no copyright