Skip to content

Repository files navigation

PyChrony: Python bindings for chrony NTP client

PyPI version Python versions CI Documentation License

Query your system's time synchronization status from Python. PyChrony provides bindings for chrony, the default NTP (Network Time Protocol) client on most Linux distributions, letting you monitor clock accuracy, sync status, and time sources programmatically.

Features

  • Read-only monitoring: Access tracking (offset, drift, stratum), sources (NTP servers, peers), statistics (samples, deviation), and RTC data
  • Pythonic API: Clean, typed interface following Python conventions
  • CFFI binding: Efficient interface to libchrony
  • Linux-first: Optimized for Linux environments with libchrony
  • Type hints: Full type annotation support for better IDE integration

Installation

pip install pychrony

Pre-built wheels include libchrony—no system dependencies needed.

Building from Source

Source installs (sdist or development) require libchrony to be installed on your system.

libchrony Package Availability

Distribution Available Install Command
Fedora 42+ ✅ Yes sudo dnf install libchrony-devel
RHEL/CentOS/Rocky/Alma 9 ✅ Yes (EPEL) sudo dnf install epel-release && sudo dnf install libchrony-devel
Debian/Ubuntu ❌ No Build from source (see below)
Alpine ❌ No Build from source (see below)
Arch Linux ❌ No Build from source (see below)

Building libchrony from Source

# Install build dependencies
# Debian/Ubuntu:
sudo apt-get install build-essential libtool libffi-dev

# Alpine:
sudo apk add gcc make libtool libffi-dev musl-dev

# Arch:
sudo pacman -S base-devel libtool libffi

# Clone and build libchrony
git clone https://gitlab.com/chrony/libchrony.git
cd libchrony
make
sudo make install prefix=/usr
sudo ldconfig

Development Install

git clone https://github.com/arunderwood/pychrony.git
cd pychrony
git submodule update --init
uv sync --all-groups
uv pip install -e .

Usage

from pychrony import ChronyConnection

with ChronyConnection() as conn:
    status = conn.get_tracking()
    print(f"Reference: {status.reference_id_name}")
    print(f"Stratum: {status.stratum}")
    print(f"Offset: {status.offset:.9f} seconds")
    print(f"Synchronized: {status.is_synchronized()}")

With no argument, pychrony tries chronyd's Unix socket and then its localhost command port, using the first that connects — the same candidates chronyc uses.

The two are not equivalent in privilege. The Unix socket is chronyd's control channel, restricted to the root or chrony user; the command port serves monitoring commands only, which is everything pychrony reads. Read-only consumers should prefer the command port and can require it:

from pychrony import ChronyConnection, Transport

with ChronyConnection() as conn:
    assert conn.transport is Transport.COMMAND_PORT
    status = conn.get_tracking()

Note that joining the chrony group does not grant access to the Unix socket. See Choosing a Transport for details.

Compatibility

  • Python: 3.10, 3.11, 3.12, 3.13, 3.14, 3.15
  • Platform: Linux (primary), other platforms where libchrony is available
  • chrony: 4.x and later

Resources

License

PyChrony is licensed under MIT. See LICENSE.

Pre-built wheels bundle libchrony which is licensed under LGPL-2.1-or-later. See LICENSES/LGPL-2.1-or-later.txt.

About

Typed Python bindings and SDK for libchrony (chronyd monitoring)

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages