{"id":19472181,"url":"https://github.com/nvms/booker","last_synced_at":"2026-06-07T20:32:35.413Z","repository":{"id":57415943,"uuid":"164153765","full_name":"nvms/booker","owner":"nvms","description":"Python task scheduling with a simple, English syntax.","archived":false,"fork":false,"pushed_at":"2019-08-16T16:44:24.000Z","size":21,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-08T05:49:32.758Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nvms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-04T20:54:07.000Z","updated_at":"2021-05-10T15:59:50.000Z","dependencies_parsed_at":"2022-09-16T08:52:32.623Z","dependency_job_id":null,"html_url":"https://github.com/nvms/booker","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvms%2Fbooker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvms%2Fbooker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvms%2Fbooker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvms%2Fbooker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nvms","download_url":"https://codeload.github.com/nvms/booker/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240692300,"owners_count":19842223,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T19:13:16.318Z","updated_at":"2026-06-07T20:32:35.141Z","avatar_url":"https://github.com/nvms.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Booker\nTested on Python 2.7, 3.5, 3.6 and 3.7.\n\nCron-esque, in-script task scheduler with an incredibly easy to use\nEnglish syntax. Booker can make calls (tasks) with specific intervals,\nstart times and end times.\n\n#### Disclaimer\nBooker is not timezone-aware and does not care about Daylight Savings Time.\n\n```python\nbooker.do(mycallable, 'every 7 days at 12:00 until 01-30-2020')\n```\n\n## Table of contents\n\n* [Basic usage](#basic-usage)\n* [Using the function decorator](#using-the-function-decorator)\n   * [Tasks that do not repeat](#tasks-that-do-not-repeat)\n      * [Starting immediately](#starting-immediately)\n      * [Starting at a specific time](#starting-at-a-specific-time)\n      * [Starting in 5 minutes](#starting-in-5-minutes)\n      * [Combining at and in](#combining-at-and-in)\n   * [Tasks that repeat with the every keyword](#tasks-that-repeat-with-the-every-keyword)\n      * [Starting now](#starting-now)\n      * [Starting at a specific time](#starting-at-a-specific-time-1)\n      * [Starting in a while](#starting-in-a-while)\n      * [Combining every with at and in.](#combining-every-with-at-and-in)\n      * [Running until a specific date and time](#running-until-a-specific-date-and-time)\n* [Using the do() method](#using-the-do-method)\n* [Task labels](#task-labels)\n   * [Assigning labels with the decorator](#assigning-labels-with-the-decorator)\n   * [Assigning labels using do()](#assigning-labels-using-do)\n* [Cancelling tasks](#cancelling-tasks)\n   * [All](#all)\n   * [By label](#by-label)\n* [Why?](#why)\n* [Q\u0026amp;A](#qa)\n\n\n## Tests\n\nPlease inspect and run tests.py yourself. All tests are passing. You\nwill need the (awesome) [freezegun](https://github.com/spulec/freezegun) library\nto run the tests.\n\n## Why?\nThere are other job scheduling libraries out there that work well,\nsuch as [schedule](https://github.com/dbader/schedule) or the \nmore feature-packed [APScheduler](https://github.com/agronholm/apscheduler).\nHowever, as far as I know, there are none that employ the English language\nas the syntax for constructing schedules. Maybe there's a good reason\nfor that. ¯\\\\\\_(ツ)_/¯\n\n__Again, why!__\n1. It's cool.\n2. Forgetting how to use it is nearly impossible.\n3. More reasons.\n\n## Basic usage\n```bash\n$ pip install booker\n```\nThe keywords `every`, `in`, `at` and `until` are explained below. They\nwork how you might expect them to work.\n```python\nimport booker\nimport time\n\ndef myfunc():\n    print('Task has been run')\n\n# Runs daily at noon until a long, long time from now.\nbooker.do(myfunc, 'every 1 day at 12:00 until 01-30-2030 12:00')\n\n# Runs at 2PM. If the current time is past 2PM, it will run tomorrow at 2PM.\nbooker.do(myfunc, 'at 14:00')\n\n# Runs every 15 minutes, starting an hour from now, indefinitely.\nbooker.do(myfunc, 'every 15 minutes in 1 hour')\n\ntry:\n    while True:\n        time.sleep(1)\nexcept KeyboardInterrupt:\n    sys.exit(0)\n```\n## Using the function decorator\n### Tasks that do not repeat\n#### Starting immediately\nThis is identical to just calling the method yourself.\n```python\n@booker.task()\ndef myfunc():\n    print('Hello')\n```\n#### Starting `at` a specific time\nUse the `at` keyword for this. This keyword expects time to be in 24 hour format (HH:MM). Seconds are not given.\n```python\n@booker.task('at 14:00')\ndef myfunc():\n    print('It is 2PM.')\n```\n#### Starting `in` 5 minutes\nUse the `in` keyword for this. The task below runs 3 days and 5 minutes from now.\n```python\n@booker.task('in 3 days 5 minutes')\ndef myfunc():\n    print('Hello')\n```\n#### Combining `at` and `in`\nYou can combine `at` and `in` to define a task that, `at` a specific time,\nwill do something `in` a certain amount of time. It does not matter what\norder you put these phrases in.\n```python\n@booker.task('in 30 minutes at 12:00')\ndef myfunc():\n    print('It is 12:30')\n```\n### Tasks that repeat with the `every` keyword\nWhen you use the `every` keyword, booker looks for additional keywords,\nprefixed by a number. Those keywords are `day[s]`, `hour[s]` or `hr[s]`,\n`minute[s]`, and `second[s]` and they should be following a number, e.g.:\n\n`7 days, 1 hour, 30 minutes, 1 second`\n\nThe commas in the syntax above aren't necessary, but you can throw them\nin there. They have no effect.\n#### Starting now\nLike the commas above, the `and` below is not required, but you can add\nit for readability. Booker will ignore what it does not understand.\n```python\n@booker.task('every 3 days and 12 hours')\n@booker.task('every 15 minutes 15 seconds')\n```\n#### Starting `at` a specific time\nYou can combine `every` with `at`.\n```python\n@booker.task('every 12 hours at 12:00')\n@booker.task('at 16:30, do this every 30 minutes')\n```\n#### Starting `in` a while\nUsing `every` with `in`, you can define a task that runs\n__in__ in a certain amount of time after the first epoch.\n```python\n@booker.task('every 1 day in 3 hours')\n@booker.task('in 30 minutes, do this every 5 seconds')\n```\n#### Combining `every` with `at` and `in`.\nCombining all of the above, the task below runs daily at 12:30. It does not\nmatter what order you put these phrases in.\n```python\n@booker.task('in 30 minutes at 12:00 every 1 day')\n```\n#### Running `until` a specific date and time\nUsing the `until` keyword, you can tell booker when to end\na task.\n\nYou need to provide the month, day, year, hour, and minute that\nyou want the task to end in `MM-DD-YYYY HH:MM` format.\n\nThe task below would run at noon, every week, until 6PM on January 2nd\nof the year 2020. Unless you had a power outage before then, or something.\n```python\n@booker.task('every 7 days at 12:00 until 01-02-2020 18:00')\n```\n## Using the `do()` method\nYou can use the `booker.do()` method to register a task with booker just as you\nwould do with the function decorator.\n```python\ndef myfunc(): ...\n\nbooker.do(myfunc, 'every 1 day starting at 12:00')\n```\nIf you build an `booker.Schedule` using `booker.get_schedule()`, you can pass\nthat Schedule object to `booker.do()`. The example below is indentical to the\nexample above.\n```python\ndef myfunc(): ...\n\nschedule = booker.get_schedule('every 1 day starting at 12:00')\nbooker.do(myfunc, schedule)\n```\n## Task labels\nYou can assign labels to tasks. Giving a task a label means that you can\ncancel it at any time.\n### Assigning labels with the decorator\n```python\n@booker.task('every 5 seconds', 'my-label')\ndef myfunc(): ...\n```\n### Assigning labels using `do()`\n```python\ndef myfunc(): ...\n\nbooker.do(myfunc, 'every 5 seconds', 'my-label')\n```\n## Cancelling tasks\n### By label\n```python\nbooker.cancel('my-label') # cancel all tasks with the label 'my-label'\n```\n### All\n```python\nbooker.cancel_all()\n```\n## Q\u0026A\n### __Q__: What exactly is a task?\n__A__: A `threading.Timer` object.\n\n\u003chr/\u003e\n\n### __Q__: Will booker block my main thread?\n__A__: No. Booker doesn't have its own thread, or control loop,\nor anything like that. It just spawns `threading.Timer` objects\nfor you when you create a task. It's up to you to keep your program\nalive throughout the duration of task execution (unless you set\n`booker.daemonize` to `False`). Usually you would do this with a\ntypical `while True: time.sleep(1)` loop.\n\nThe example below would quit immediately\nand the task that was defined would never run because, by default,\nbooker daemonizes all of its tasks. You can disable this by setting\n`booker.daemonize` to `False`.\n```python\n# This example quits immediately\nimport booker\n\ndef myfunc():\n    ...\n\nbooker.do(myfunc, 'in 10 seconds')\n```\nThis example, on the other hand, would block your main thread\nand prevent the program from exiting until the task has finished.\n```python\n# This example quits after 10 seconds has passed\nimport booker\n\nbooker.daemonize = False\n\ndef myfunc():\n    ...\n\nbooker.do(myfunc, 'in 10 seconds')\n```\n\n\u003chr/\u003e\n\n### __Q__: It is 6PM. What happens with this task?\n```python\nbooker.do(myfunc, 'at 12:00')\n```\n__A__: It will run, once, tomorrow at noon.\n\n\u003chr/\u003e\n\n### __Q__: I have a string: `2 hours, 59 minutes, 40 seconds`, and I want to run a task 5 minutes after that. How?\n\n__A__: Use `booker.get_schedule` to get a `booker.Schedule` and add 300 seconds to its `tts` (time-to-start) property.\n```python\nschedule = booker.get_schedule('in 2 hours, 59 minutes, 40 seconds')\nschedule.tts = schedule.tts + 300\n\nbooker.do(myfunc, schedule)\n```\n\n\u003chr/\u003e\n\n### __Q__: How do I pass arguments to a task?\n\n__A__: Use a lambda.\n```python\ndef myfunc(myarg):\n    print('Hello, {}'.format(myarg))\n\nbooker.do(lambda: myfunc('world!'), 'in 5 seconds')\n```\n\n\u003chr/\u003e\n\n### __Q__: Can I view the status of a task?\n\n__A__: From `example.py`:\n```python\nfor task in booker.tasks():\n    print(task)\n```\n__output:__\n```bash\nRepeatingTask: [__main__.pong] [interval: 1s] [tts: 2s] [running in: 0.00s] [until: indefinitely] [label: my-pong-task]\nSingleTask: [__main__.print_task_status] [tts: 3s] [finished 0.00s ago]\nSingleTask: [__main__.\u003clambda\u003e] [tts: 12s] [running in: 9.00s]\nSingleTask: [__main__.\u003clambda\u003e] [tts: 19s] [running in: 16.00s]\nSingleTask: [booker.cancel_all] [tts: 20s] [running in: 17.00s]\nRepeatingTask: [__main__.print_time] [interval: 1s] [tts: 0s] [running in: 0.00s] [until: indefinitely]\nRepeatingTask: [__main__.never_run] [interval: 1s] [tts: 5s] [until: 3s has passed]\nSingleTask: [__main__.\u003clambda\u003e] [tts: 7s] [running in: 4.00s]\nRepeatingTask: [__main__.ping] [interval: 1s] [tts: 0s] [running in: 0.00s] [until: indefinitely] [label: my-ping-task]\nSingleTask: [__main__.in_five_seconds] [tts: 5s] [running in: 2.00s]\nSingleTask: [__main__.in_ten_seconds] [tts: 10s] [running in: 7.00s]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvms%2Fbooker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnvms%2Fbooker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvms%2Fbooker/lists"}