Skip to content

Headers

Matthew Harrigan edited this page Aug 7, 2021 · 1 revision

Headers

YDL is the communication that enables shepherd to run asynchronously. YDL is based on headers, which are defined in utils.py.

Headers are a special data type created with some python magic, but you can generally treat them as functions, which spit out the correct data to a YDL send. Additionally, headers have a unique name which you can access via .name, and a YDL target, accessible via .target.

The header datatype is defined in header.py.

Defining a header

As mentioned before, a header is defined in utils.py. In order to make definition easy and short, we are using special python syntax. A new header is defined as so:

@header(YDL_TARGETS.SHEPHERD, "example_header")
    def EXAMPLE_HEADER(arg : str):
        """
        source: UI. An example header.
        contains:
            arg - a string
        """
        if len(arg) > 10:
          raise Exception("use a shorter string")

Lets break down this definition. We are piggybacking off the function definition with an extra @header decorator. This definition contains the following parts:

  • Decorator. The decorator sits at the beginning of the definition and contains 2 arguments:
    • Target. The YDL target that this header is intended for.
    • Name. The lowercase and javascript friendly name of the header.
  • Function definition. A function definition allows us to quickly and easily list arguments and add a docstring, as well as create a type-checking function if we wish to.
    • Function name. The name that we will use to reference this header in the python backend. This should be uppercase and should match the name defined in the decorator.
    • Function arguments. The arguments for the YDL send. These may be typed, and if they are typed, typing will be enforced at runtime. No positional-only arguments are allowed here (if you don't know what those are then don't worry, you aren't using them).
    • Function docstring. The docstring to describe the header. This docstring will be copied from this function declaration and into the header itself.
    • Function body. A function body may be provided. This should be used for extra data type checking, and should raise exceptions when it finds an issue. Any returned values will be discarded.

Using a header

Headers can be used in two contexts, either to send a message, or to compare to a received message.

When used to send a message, you would do something like:

ydl_send(*UI_HEADER.EXAMPLE_HEADER("hello"))

This works because when the header is called, it type checks it's arguments and then returns a tuple of the target, the lowercase javascript friendly name, and the arguments in a keyword dictionary. This tuple is then unpacked by the * and used for ydl_send.

When used to compare to a received message, you must access the .name field of the header and compare that with the lowercase name that was packed with the message. For example:

if message_header == UI_HEADER.EXAMPLE_HEADER.name

You may also use str() to get the lowercase name.