Writing Scripts

What are Scripts

To tell Avame to do your jobs, you need to tell Avame how to do it imperatively. The instructions are expressed as a script in Python-like programming language. It sounds scary at the first place to writing scripts in a programming language for regular users. It ends up not so hard at all.

Differences from Regular Code

The syntax is intentionally very limited so that it’s more approachable than full-featured Python codes. The document is not intended to describe all the syntax as it’s a proper subset of Python’s. Compared to regular Python, following are removed features:

  1. No import statement
  2. No while control loop
  3. No print statement
  4. Names start with double underscores are prohibited, e.g. ‘__class__’.
  5. No function definition
  6. No class definition

Common Libraries

It’s not supported to import modules for scripts, so some standard libraries from Python runtime are selected and made available. The modules provided:

  1. datetime
  2. collections
  3. calendar
  4. heapq
  5. bisect
  6. array
  7. queue or Queue
  8. string
  9. re
  10. math
  11. random
  12. json
  13. base64
  14. binascii
  15. hashlib
  16. hmac

In addition to standard libraries, lxml is available for XML/HTML parsing.

Perform Actions

Besides the common libraries, scripts can perform various actions, each of which are explicitly registered functions and are intended for use by scripts.

The syntax to invoke an action is like follow:

ava.do(action_name, **kwargs)

, where action_name is in a format like ‘mod_name.func_name’. For example, ‘imap.check_gmail’ is the action name from imap module to check GMail.

ava.do function returns a task object whose essential methods are:

  1. result(blocked=True, timeout=None)

    Wait for the task to finish and return the result (or raise an exception). By default, the method blocks the caller. But can be made to work asynchronously. If blocked is False and the task is not stopped, a Timeout exception is raised. If timeout parameter is given, a Timeout exception will be raised if expired.

  2. stopped()

    Check if the task is finished or failed without blocking.

  3. finished()

    Check if the task is completed successfully.

  4. failed()

    Check if the task failed.

The execution of an action is represented as a task. Multiple tasks can be issued concurrently. At times, it’s needed to wait for tasks to finish. To coordinate tasks, a script may use following method to wait for tasks.

ava.wait(tasks, timeout=10)

,where tasks is a list of task objects; timeout is a timeout interval in seconds. There is an additional argument count which specify how many tasks to wait for before returning.

Built-in Actions

User Module

  • user.notify

    Notify owner with a message and title.

Request Module

Make methods from requests library available as actions.

  • requests.head
  • requests.get
  • requests.put
  • requests.patch
  • requests.delete
  • requests.post

Loop Control

The only supported loop control for scripts is for statement. for loop is usually used to iterate a finite number of elements. In case a indefinite loop is needed, following construct can be used:

for it in ava.schedule:
    ...

ava.schedule is a special generator that returns counting number from 1 for each iteration. By default, the interval between intervals are 1 minute. Following are more examples:

1-minute interval

for it in ava.schedule.every(1).minute

5-minute interval

for it in ava.schedule.every(5).minutes

There are other supported interval units like second,`seconds`, hour, hours, day and days.

The total number of looping can also be control by providing a counts value. For example:

for it in ava.schedule.count(5).every().minute:
    ...

Above code snippet loops 5 times and waits for 1 minute before an iteration.

Example

Following script is for checking a GMail account with IMAP protocol every minute:

last_unseen = 0

for it in ava.schedule.every(1).minute:
    check_task = ava.do('imap.check_gmail',
                        username='username@gmail.com',
                        password='password')

    messages, unseen = check_task.result()
    if unseen > 0 and unseen != last_unseen:
        last_unseen = unseen
        ava.do('user.notify',
               message="You got %d new messages." % unseen,
               title="You Got Mails from GMail")