schedule

In-process Python job scheduling with a friendly, readable syntax for running functions on a fixed cadence.

Library
PyPI
v1.2.2
12,263stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
43/100Fair
Development Activity0
Maintenance0
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
80/100Excellent
Architecture78
Code Quality88
Innovation55
Learning Curve100

schedule is a lightweight, pure-Python library for running functions periodically inside a long-lived process, without needing cron, a message broker, or any external service. Jobs are declared with a fluent, English-like syntax such as schedule.every(10).minutes.do(job), and executed by calling run_pending() from your own loop.

It has zero required dependencies, supports second-through-week interval units, specific times of day, weekday-only jobs, randomized intervals, deadline-based cancellation, and optional pytz-backed timezone handling, making it a common choice for small scripts and services that want recurring tasks without adopting a full task-queue system like Celery.

What You Get

  • A single-file, pure-Python scheduler with no required runtime dependencies
  • A chainable API for expressing intervals in seconds, minutes, hours, days, and weeks
  • Built-in support for weekday-specific and time-of-day (.at()) scheduling
  • Optional pytz-backed timezone support for .at() calls via the timezone extra

Common Use Cases

  • Running periodic maintenance or polling functions inside a long-lived process
  • Replacing ad hoc time.sleep() loops with declarative interval scheduling
  • Lightweight recurring-task scheduling for scripts that don’t need a broker-backed queue
  • Timezone-aware daily jobs for services operating across regions

Under The Hood

Architecture The library is a single module (schedule/__init__.py) containing two classes: Scheduler (holds a list of Job instances and exposes run_pending/run_all/get_jobs/clear/cancel_job/every) and Job (a fluent builder that accumulates interval/unit/at_time/tags via chained property access and terminates with .do(), which computes next_run via _schedule_next_run() and registers itself on the scheduler’s job list). Module-level functions (every, run_pending, repeat, etc.) are thin wrappers around a shared default_scheduler singleton, so most user code never touches Scheduler directly. Job.__lt__ makes jobs sortable by next_run, which run_pending() relies on to execute due jobs in time order. There’s no internal threading or event loop — callers poll run_pending() from their own loop, and timezone correctness for .at() is isolated to a handful of _correct_utc_offset/_move_to_at_time helpers, keeping the core execution model simple and traceable end to end.

Tech Stack Pure Python 3.7+ with zero required runtime dependencies (dependencies = [] in pyproject.toml); the only optional dependency is pytz, gated behind the timezone extra and imported lazily inside Job.at() only when a timezone argument is passed. Packaging uses setuptools with a pyproject.toml build-system and dynamic metadata. Testing runs through tox across multiple Python versions (with and without pytz) using pytest, pytest-cov, and mypy, orchestrated in CI via tox-gh-actions on GitHub Actions with Coveralls reporting. Documentation is built with Sphinx and published to Read the Docs. There are no database, network, or web-framework dependencies of any kind.

Code Quality The repo has extensive test coverage — a single test file with dozens of test methods covering interval calculations, .at() time parsing and validation, timezone/DST edge cases (using mocked datetimes and POSIX TZ strings for several real timezones), tag filtering, cancellation, and randomized intervals. Tests use unittest.mock and the standard-library unittest.TestCase, run through tox/pytest-cov, and CI additionally runs mypy for static type-checking against a fully type-annotated source. Error handling is explicit and typed — a small exception hierarchy (ScheduleError -> ScheduleValueError -> IntervalError) is raised for misuse rather than failing silently. Code style is enforced via black --check in a dedicated tox environment, and naming is consistent throughout.

What Makes It Unique schedule’s distinguishing choice is its fully in-process, English-readable builder syntax that requires no broker, daemon, or config file — unlike Celery or APScheduler it has zero infrastructure to run, at the cost of only firing while the host process’s own loop calls run_pending(). Its randomized-interval and deadline-based auto-cancellation features are relatively uncommon conveniences for lightweight schedulers, and the DST-aware timezone-correction logic for pinned .at() calls solves a genuinely fiddly correctness problem most simple schedulers ignore. These are incremental refinements on a well-established declarative in-process scheduling pattern rather than a novel architecture — a well-executed take on a known idea rather than a groundbreaking one.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search