Skip to main content

Calendar scheduler

Project description

Calendar Scheduler for Recurring Events

PyPI version Pylint Unit tests

ru

Features

  • Executes an action function on a schedule.
  • Thread-safe: events can be added and canceled from different threads.
  • Supports intervals from milliseconds to years.
  • Uses the standard sched scheduler.
  • Timezone support.
  • Syntax similar to datetime.
  • Events can be added at any time: before or after the scheduler starts, and from any thread.
  • No additional packages required.

Installation

Install via pip:

pip install calsched

Install via uv:

uv pip install calsched

Import

from calsched import CalendarScheduler

Creating the Scheduler

scheduler = CalendarScheduler()

Running the Scheduler

Start the scheduler using the run() method:

scheduler.run()

However, it will immediately exit if no events are scheduled. At least one event must be scheduled before starting.

Example that prints the current time every second:

import datetime
from calsched import CalendarScheduler

def print_time():
    print(datetime.datetime.now())

scheduler = CalendarScheduler()
scheduler.enter_every_second_event(action=print_time)
scheduler.run()

In this case, run() blocks the thread in which it is called.

The action function is executed in the same thread as the run() method.

To allow adding events after the scheduler has started, you can add a placeholder event before calling run() to keep the scheduler active:

scheduler = CalendarScheduler()
stub_event = scheduler.enter_hourly_event(action=lambda: None)
scheduler.run()

You can stop run() by canceling the placeholder event:

scheduler.cancel(stub_event)

If there are multiple events, you need to cancel all events to stop the scheduler.

Example of running in a separate thread:

import datetime
import threading
from time import sleep
from calsched import CalendarScheduler

def print_time():
    print(datetime.datetime.now())

scheduler = CalendarScheduler()
stub_event = scheduler.enter_hourly_event(action=lambda: None)
thread = threading.Thread(target=scheduler.run)
thread.start()
sleep(1.0)

event = scheduler.enter_every_second_event(action=print_time)
sleep(5.0)
scheduler.cancel(stub_event)
scheduler.cancel(event)
thread.join()

Adding Events

To add events, use the enter_*_event() methods:

  • enter_every_millisecond_event(action=my_action, interval=N)my_action() will be called every N milliseconds.
  • enter_every_second_event(action=my_action, interval=N)my_action() will be called every N seconds.
  • enter_every_minute_event(action=my_action, interval=N)my_action() will be called every N minutes.
  • enter_hourly_event(action=my_action, interval=N)my_action() will be called every N hours.
  • enter_daily_event(action=my_action, interval=N)my_action() will be called every N days.
  • enter_weekly_event(action=my_action, interval=N)my_action() will be called every N weeks.
  • enter_monthly_event(action=my_action, interval=N)my_action() will be called every N months.
  • enter_yearly_event(action=my_action, interval=N)my_action() will be called every N years.

The interval parameter must be greater than or equal to 1 and has no upper limit.

By default, the interval is 1. That is, if you do not specify the interval parameter, the event will be triggered every 1 second, 1 minute, etc., depending on the method. The exception is enter_every_millisecond_event(), where the default interval is 100 milliseconds, since a 1-millisecond interval is not feasible on real machines.

Example of a daily event that prints the current time:

import datetime
from calsched import CalendarScheduler
    
def print_time():
    print(datetime.datetime.now())

scheduler = CalendarScheduler()
scheduler.enter_daily_event(action=print_time)
scheduler.run()

Time Parameters

An event can be scheduled for a specific moment: a particular second, minute, hour, day, and/or month.

The enter_yearly_event() method allows you to specify month, day, hour, minute, and second. Example: an event that runs 5 minutes before New Year (i.e., December 31 at 23:55:00):

scheduler.enter_yearly_event(action=my_action, month=12, day=31, hour=23, minute=55, second=0)

For monthly events, you can specify day, hour, minute, and second. Example: an event that runs on the first day of each month at 04:00:00:

scheduler.enter_monthly_event(action=my_action, day=1, hour=4, minute=0, second=0)

For monthly events, you cannot specify month, as it does not make sense. Similarly for other event types:

scheduler.enter_weekly_event(action=my_action, weekday=3, hour=4, minute=0, second=0)
scheduler.enter_daily_event(action=my_action, hour=4, minute=0, second=0)
scheduler.enter_hourly_event(action=my_action, minute=0, second=0)
scheduler.enter_every_minute_event(action=my_action, second=0)

The enter_every_second_event and enter_every_millisecond_event methods do not allow specifying execution time.

Time parameter value ranges:

  • 0 <= second <= 59,
  • 0 <= minute <= 59,
  • 0 <= hour <= 23,
  • 1 <= day <= 31,
  • 0 <= weekday <= 6 (Monday is 0, Sunday is 6),
  • 1 <= month <= 12.

In enter_monthly_event() and enter_yearly_event(), if the specified day is greater than the number of days in the month, the event will be executed on the last day of the month. For example, if you specify day=31, the event will run on January 31, then on February 28 or 29 (in a leap year).

Start and End Time for Periodic Events

You can specify the start and end time for a periodic event using the start_time and end_time parameters. If not specified, the event will run indefinitely starting from the current time.

  • start_time – time of the first execution.
  • end_time – time until which the event will be executed.

The start_time and end_time parameters are specified as timestamps (seconds since the Unix epoch, i.e., January 1, 1970). Typically, these values are obtained using time.time() or datetime.timestamp().

The time range is from start_time up to, but not including, end_time.

All enter_*_event() methods allow specifying start_time and end_time. Example: an event that runs every day from January 1, 2024, to January 1, 2025 (not inclusive):

start_time = datetime.datetime(2024, 1, 1, 0, 0, 0).timestamp()
end_time = datetime.datetime(2025, 1, 1, 0, 0, 0).timestamp()
scheduler.enter_daily_event(action=my_action, start_time=start_time, end_time=end_time)

Action Function Arguments

The action function can accept arguments. Use the action_args parameter for positional arguments and action_kwargs for keyword arguments.

All enter_*_event() methods allow specifying action_args and action_kwargs.

Example:

def my_action(arg1, arg2):
    pass

scheduler.enter_daily_event(action=my_action, action_args=("Hello",), action_kwargs={"arg2": 123})

The scheduler will call the function as follows:

my_action("Hello", arg2=123)

Project details


Download files

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

Source Distribution

calsched-1.1.1.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

calsched-1.1.1-py3-none-any.whl (8.1 kB view details)

Uploaded Python 3

File details

Details for the file calsched-1.1.1.tar.gz.

File metadata

  • Download URL: calsched-1.1.1.tar.gz
  • Upload date:
  • Size: 12.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.12

File hashes

Hashes for calsched-1.1.1.tar.gz
Algorithm Hash digest
SHA256 1940dd0bcf227cb51cfd403bc472c16965bc9b694143cd4837f1436d03a80459
MD5 22e111cafe0d8c1bbdd435db57624dd1
BLAKE2b-256 30170b8920efffe73c87e6240964597317673c109240df1c7199f059db4220bd

See more details on using hashes here.

File details

Details for the file calsched-1.1.1-py3-none-any.whl.

File metadata

  • Download URL: calsched-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 8.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.12

File hashes

Hashes for calsched-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 76414f703f76fa1f04875455a581247aa332ad7c6a9a5843870b78da80dd5740
MD5 727dc13296e3e0618f11d9cd5ad13b07
BLAKE2b-256 26ee281f4616171651f528eba903bf6dde8f7d7e544933a97ec0be672a11a853

See more details on using hashes here.

Supported by

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