Schemdule is a tiny tool using script as schema to schedule one day and remind you to do something during a day.
Install
Use pip:
pip install schemdule
Or use pipx:
# Install pipx
pip install --user pipx
pipx ensurepath
# Install Schemdule
pipx install schemdule
# Install extension
pipx inject schemdule schemdule-extensions-{extension name}
# Upgrade
pipx upgrade schemdule --include-injected
Usage
Write a Schema
An example schema.
# Schema
at("6:30", "Get up")
cycle("8:00", "12:00", "00:30:00", "00:10:00", "Working")
# Import other schema by `load` function
# load("other_schema.py")
prompter.useTkinterMessageBox()
# ext("simplegui") # use simplegui extension (package schemdule-extensions-simplegui)
# use multiple prompter:
# prompter.useBroadcaster().useConsole().useMessageBox(True)
The built timetable is like the following one from the results of the command schemdule run schema.py --preview
.
🕡 06:30:00 - 🕗 08:00:00 🔔 Get up
🕗 08:00:00 - 🕣 08:30:00 💼 Working (cycle 1 starting)
🕣 08:30:00 - 🕣 08:40:00 ☕ Working (cycle 1 resting starting)
🕣 08:40:00 - 🕘 09:10:00 💼 Working (cycle 2 starting)
🕘 09:10:00 - 🕘 09:20:00 ☕ Working (cycle 2 resting starting)
🕘 09:20:00 - 🕤 09:50:00 💼 Working (cycle 3 starting)
🕤 09:50:00 - 🕙 10:00:00 ☕ Working (cycle 3 resting starting)
🕙 10:00:00 - 🕥 10:30:00 💼 Working (cycle 4 starting)
🕥 10:30:00 - 🕥 10:40:00 ☕ Working (cycle 4 resting starting)
🕥 10:40:00 - 🕚 11:10:00 💼 Working (cycle 5 starting)
🕚 11:10:00 - 🕚 11:20:00 ☕ Working (cycle 5 resting starting)
🕚 11:20:00 - 🕦 11:50:00 💼 Working (cycle 6 starting)
🕦 11:50:00 - 🕦 11:50:00 ☕ Working (cycle 6 resting starting)
Run
# load and run from the schema
schemdule run schema.py
# or use python
# python -m schemdule run schema.py
# preview the built timetable
schemdule run schema.py --preview
# try the builtin demo (just for testing)
schemdule demo
Schema Specification
Schema is a pure python script, so you can use any python statement in it.
Schemdule provide at
, cycle
, load
and ext
functions for registering events, and a PrompterBuilder
variable named prompter
to config prompter.
These functions and variable can be accessed and modified in the variable
env
, a dict for these items provided by Schemdule. You can change theenv
variable to change the execute environment forload
function.
# raw_time can be {hh:mm} or {hh:mm:ss} or a datetime.time object
def at(rawTime: Union[str, time], message: str = "", payload: Any = None) -> None:
# register an event at time with message
# if payload is a PayloadBuilder, Schemdule will build the final payload automaticly
...
def cycle(rawStart: Union[str, time], rawEnd: Union[str, time], rawWorkDuration: Union[str, time, timedelta], rawRestDuration: Union[str, time, timedelta], message: str = "", workPayload: Optional[Callable[[int], Any]] = None, restPayload: Optional[Callable[[int], Any]] = None) -> None:
# register a series of events in cycle during start to end
# the duration of one cycle = workDuration + restDuration
# For each cycle, register 2 event: cycle starting, cycle resting
# workPayload and restPayload is the payload generator such as:
# def generator(index: int) -> Any: ...
# if the returened payload is a PayloadBuilder, Schemdule will build the final payload automaticly,
...
def loadRaw(source: str) -> None:
# load from a schema source code
...
def load(file: str, encoding: str = "utf8") -> None:
# load from a schema source code file
...
def ext(name: Optional[str] = None) -> None:
# use an extension or use all installed extensions (if name is None)
# provided by packages `schemdule-extensions-{extension name}`
...
def payloads() -> PayloadBuilder:
# create a payload builder
...
def prompters() -> PrompterBuilder:
# create a prompter builder
...
# the class PayloadBuilder
class PayloadBuilder:
def use(self, payload: Any) -> "PayloadBuilder": ...
# the class of the variable `prompter`
class PrompterBuilder:
def use(self, prompter: Union[Prompter, "PrompterBuilder"]) -> "PrompterBuilder":
def useBroadcaster(self, final: bool = False) -> "PrompterBuilder": ...
def useSwitcher(self, final: bool = False) -> "PrompterBuilder": ...
def useConsole(self, final: bool = False) -> "PrompterBuilder": ...
def useCallable(self, final: bool = False) -> "PrompterBuilder": ...
def useTkinterMessageBox(self, final: bool = False) -> "PrompterBuilder": ...
def clear(self) -> "PrompterBuilder": ...
# the default value of the variable `prompter`
def default_prompter_builder() -> PrompterBuilder:
prompter = PrompterBuilder()
prompter.useSwitcher().useConsole().useCallable(True).useTkinterMessageBox()
return prompter
Here are the type annotions for schema.
# Type annotions
from typing import Callable, Union, Any, Dict, Optional
from datetime import time, timedelta
from schemdule.prompters.builders import PrompterBuilder, PayloadBuilder
from schemdule.prompters import Prompter, PrompterHub
at: Callable[[Union[str, time], str, Any], None]
cycle: Callable[[Union[str, time], Union[str, time], Union[str, time, timedelta], Union[str, time, timedelta], str, Optional[Callable[[int], Any]], Optional[Callable[[int], Any]]], None]
loadRaw: Callable[[str], None]
load: Callable[[str], None]
ext: Callable[[Optional[str]], None]
payloads: Callable[[], PayloadBuilder]
payloads: Callable[[], PrompterBuilder]
prompter: PrompterBuilder
env: Dict[str, Any]