Skip to main content

A simple schedule parser/runner with a convienient syntax.

Project description

pyfuncschedule

A package that allows python functions to be repeatedly run according to a given schedule composed of a series of time intervals.

Usage & Syntax

Function schedules are written as config files with a custom format. There is not as yet a standardised file extention for such configuration files, we might use .fsch.

The simplest func schedule has the following syntax:

ACTION(ARG1, ARG2, ...) @ [I1, I2, ...]:N

White spaces (including newlines and tabs) are ignored (unless part of str literals). Comments work similar to python and use # to being.

Example 1 - Simple Schedule

# this is a comment
foo(1) @ [1,2,3]:1

Running this schedule will execute the function foo with arguments 1 at t=1,3,6. Notice that the schedule is specified in relative time in seconds since the previous function execution (int or float).

Example 2 - Repeating Schedule Blocks

foo() @ [1,2]:2

foo will be executed at t=1,3,4,6. The :N value specifies the number of times to repeat the given schedule block.

Example 3 - Repeating Forever

foo() @ [1]:*

foo will be executed at t=1,2,3,4,... and continue until the schedule runner is terminated.

Example 4 - Nesting Schedules

It is possible to nest schedules to acheive more complex timings.

foo() @ [[1,2]:2]:2

We can unpack this schedule as follows:

[1,2]:2 -> [1,2,1,2] -> t=[1,3,4,6]
[[1,2]:2]:2 -> [1,2,1,2,1,2,1,2] -> t=[1,3,4,6,7,9,10,12]

Nested schedules are unpacked lazily.

Example 5 - Function Calls

Using static timings for schedules is useful in many scenarios, but in some cases we may like to determine these timings during execution. This can be done by registering functions to our schedule (see section TODO). The syntax for this is the same as a function call in python.

foo() @ [uniform(0,1)]:*

This will execute foo() at some time sampled uniformly in the interval [0,1]. The uniform function is called repeatedly to produce new random intervals. The function is called to produce its value at the moment of the last execution of foo. If the function call is the first element in the schedule, it will be called at time 0 (foo is typically not executed at this time).

Example 6 - Function Data

Many of the Python built-in data types: 'int','float','bool','str','list','dict' can be used as arguments to function calls. It is also possible to nest function calls, making it possible to pass around custom data types.

foo(["a","b"]) @ [bar(baz(1), baz(2))]:*

Parsing func schedules

parsing a schedule is easy:

  1. create a parser
from pyfuncschedule import ScheduleParser
parser = ScheduleParser()
  1. register the functions that you want to use:
def foo():
    ...
def bar():
    ...
# use register_action for the function you wish to call after each interval.
parser.register_action(foo)
# use register function for functions that are used in the intervals.
parser.register_function(bar)
  1. define or load your schedules
schedules_str = """foo1()@[bar(),2]:1"""

NOTE: as of version 0.1 schedules must be provided as a str there is no option for loading directly from a file.

  1. parse and resolve
schedules = parser.resolve(parser.parse(schedule_str))

This will parse the schedule and resolve any functions that have been registered.

Running func schedules

The result is a list of schedule objects which act like iterables providing (interval, func). One way to run a given schedule is to iterate over it and to wait in a new thread, for example:

for (interval, action) in schedules[0]:
    time.sleep(interval)
    action()

Instead, we can use asyncio and the schedule.stream() method, which will run the schedule in an async context.

import time
import asyncio
from pyfuncschedule import ScheduleParser

async def main():
    start_time = time.time()
    schedules_str = """foo()@[1]:3 \n bar()@[2]:2"""
    parser = ScheduleParser()

    def foo():
        return f"foo: {time.time() - start_time}"

    def bar():
        return f"bar: {time.time() - start_time}"

    parser.register_action(foo)
    parser.register_action(bar)
    schedules = parser.resolve(parser.parse(schedules_str))

    async def task(schedule):
        async for x in schedule.stream():
            print(x)

    tasks = []
    for schedule in schedules:
        tasks.append(asyncio.create_task(task(schedule)))
    await asyncio.gather(*tasks)

asyncio.run(main())

The above creates an asyncio task for each schedule, this gives more control over how each schedule will be run. However if we have many schedules we might instead want all schedules to be "merged" into one. This can be acheived by using the parser.stream(schedules) method, see below:

import time
import asyncio
from pyfuncschedule import ScheduleParser

async def main():
    start_time = time.time()
    schedules_str = """foo()@[1]:3 \n bar()@[2]:2"""
    parser = ScheduleParser()

    def foo():
        return f"foo: {time.time() - start_time}"

    def bar():
        return f"bar: {time.time() - start_time}"

    parser.register_action(foo)
    parser.register_action(bar)
    schedules = parser.resolve(parser.parse(schedules_str))
    # safe async iter context
    async with parser.stream(schedules) as stream:
        # iterate asynchronously
        async for x in stream:
            print(x)

asyncio.run(main())

Contributing

If you discover a bug or feel something is missing from this package please create an issue and feel free to contribute!

Project details


Release history Release notifications | RSS feed

This version

0.1

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyfuncschedule-0.1.tar.gz (23.6 kB view details)

Uploaded Source

Built Distribution

pyfuncschedule-0.1-py3-none-any.whl (20.8 kB view details)

Uploaded Python 3

File details

Details for the file pyfuncschedule-0.1.tar.gz.

File metadata

  • Download URL: pyfuncschedule-0.1.tar.gz
  • Upload date:
  • Size: 23.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.10.14

File hashes

Hashes for pyfuncschedule-0.1.tar.gz
Algorithm Hash digest
SHA256 2e4d5dffa90b7d16d8a0826446b6e13c3f553ae31bfdada923b18748eea2d22f
MD5 493e7a8818332e79ed70b8a6e22fd7c5
BLAKE2b-256 a88ea73a19e4156fca7700b23a618853bde24f422c2b2aabcc326b2f3100f925

See more details on using hashes here.

File details

Details for the file pyfuncschedule-0.1-py3-none-any.whl.

File metadata

  • Download URL: pyfuncschedule-0.1-py3-none-any.whl
  • Upload date:
  • Size: 20.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.10.14

File hashes

Hashes for pyfuncschedule-0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 03ada132c8d9bcca19b2b55715699d675231d1845cc9e571d37ef410ff88d91b
MD5 af540de102b69d75cea8e2b737abea7b
BLAKE2b-256 9d64cd3cc410f84495a84839f4dd3c289e7899e57e738967952cb25d958addae

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page