-
Notifications
You must be signed in to change notification settings - Fork 2
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.
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.
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.