Skip to content

Schedulers

Unix (cron)

chico.schedulers.unix

Unix cron scheduler backend for chico.

Uses crontab to install, remove, and query a recurring entry that runs chico sync automatically on macOS and Linux.

Supports intervals of 1–59 minutes (the cron minute field range). For longer intervals use the Windows Task Scheduler backend instead.

Example usage::

from chico.schedulers.unix import install, uninstall, is_installed, query

install(interval_minutes=30)
print(is_installed())   # True
print(query())          # {"Schedule": "*/30 * * * *", "Command": "..."}
uninstall()

SchedulerError

Bases: Exception

Raised when a cron operation fails.

Source code in chico/schedulers/unix.py
class SchedulerError(Exception):
    """Raised when a cron operation fails."""

install(interval_minutes, command=None)

Add or update the chico sync cron entry.

Removes any existing chico entry before adding the new one, so this is safe to call repeatedly or to change the interval.

Parameters:

Name Type Description Default
interval_minutes int

How often to run, in minutes. Must be between 1 and 59.

required
command str | None

The shell command to schedule. Defaults to python -m chico sync.

None

Raises:

Type Description
SchedulerError

If the interval is out of range or crontab exits non-zero.

Source code in chico/schedulers/unix.py
def install(interval_minutes: int, command: str | None = None) -> None:
    """Add or update the chico sync cron entry.

    Removes any existing chico entry before adding the new one, so this
    is safe to call repeatedly or to change the interval.

    Parameters
    ----------
    interval_minutes:
        How often to run, in minutes. Must be between 1 and 59.
    command:
        The shell command to schedule. Defaults to ``python -m chico sync``.

    Raises
    ------
    SchedulerError
        If the interval is out of range or ``crontab`` exits non-zero.
    """
    if not 1 <= interval_minutes <= 59:
        raise SchedulerError(
            f"interval_minutes must be between 1 and 59 on Unix, got {interval_minutes}"
        )

    lines = [line for line in _crontab_lines() if CRON_MARKER not in line]
    cmd = command or f"{sys.executable} -m chico sync"
    lines.append(f"*/{interval_minutes} * * * * {cmd}  {CRON_MARKER}")
    _write_crontab(lines)

is_installed()

Return True if a chico sync cron entry exists.

Source code in chico/schedulers/unix.py
def is_installed() -> bool:
    """Return ``True`` if a chico sync cron entry exists."""
    return any(CRON_MARKER in line for line in _crontab_lines())

query()

Return the schedule and command from the chico cron entry.

Returns None if no entry is installed.

Source code in chico/schedulers/unix.py
def query() -> dict[str, str] | None:
    """Return the schedule and command from the chico cron entry.

    Returns ``None`` if no entry is installed.
    """
    for line in _crontab_lines():
        if CRON_MARKER not in line:
            continue
        entry = line.replace(CRON_MARKER, "").strip()
        parts = entry.split(None, 5)
        schedule = " ".join(parts[:5]) if len(parts) >= 5 else entry
        command = parts[5].strip() if len(parts) > 5 else ""
        return {"Schedule": schedule, "Command": command}
    return None

uninstall()

Remove the chico sync cron entry.

Raises:

Type Description
SchedulerError

If no chico entry exists or crontab exits non-zero.

Source code in chico/schedulers/unix.py
def uninstall() -> None:
    """Remove the chico sync cron entry.

    Raises
    ------
    SchedulerError
        If no chico entry exists or ``crontab`` exits non-zero.
    """
    lines = _crontab_lines()
    new_lines = [line for line in lines if CRON_MARKER not in line]
    if len(new_lines) == len(lines):
        raise SchedulerError("No chico scheduled task found.")
    _write_crontab(new_lines)

Windows (Task Scheduler)

chico.schedulers.windows

Windows Task Scheduler backend for chico.

Uses schtasks.exe to create, remove, and query a recurring task that runs chico sync automatically.

Example usage::

from chico.schedulers.windows import install, uninstall, is_installed, query

install(interval_minutes=30)
print(is_installed())   # True
print(query())          # {"Status": "Ready", "Last Run Time": "...", ...}
uninstall()

SchedulerError

Bases: Exception

Raised when a Task Scheduler operation fails.

Source code in chico/schedulers/windows.py
class SchedulerError(Exception):
    """Raised when a Task Scheduler operation fails."""

install(interval_minutes, command=None)

Create or update the ChicoSync scheduled task.

Schedules python -m chico sync to run every interval_minutes minutes for the current user. Safe to call when the task already exists — the /F flag silently overwrites it.

Parameters:

Name Type Description Default
interval_minutes int

How often to run, in minutes. Must be between 1 and 1439.

required
command str | None

The shell command to schedule. Defaults to python -m chico sync.

None

Raises:

Type Description
SchedulerError

If schtasks exits with a non-zero return code.

Source code in chico/schedulers/windows.py
def install(interval_minutes: int, command: str | None = None) -> None:
    """Create or update the ChicoSync scheduled task.

    Schedules ``python -m chico sync`` to run every ``interval_minutes``
    minutes for the current user. Safe to call when the task already exists
    — the ``/F`` flag silently overwrites it.

    Parameters
    ----------
    interval_minutes:
        How often to run, in minutes. Must be between 1 and 1439.
    command:
        The shell command to schedule. Defaults to ``python -m chico sync``.

    Raises
    ------
    SchedulerError
        If ``schtasks`` exits with a non-zero return code.
    """
    if not 1 <= interval_minutes <= 1439:
        raise SchedulerError(
            f"interval_minutes must be between 1 and 1439, got {interval_minutes}"
        )

    cmd = command or f'"{sys.executable}" -m chico sync'
    result = _run(
        "/Create",
        "/TN",
        TASK_NAME,
        "/TR",
        cmd,
        "/SC",
        "MINUTE",
        "/MO",
        str(interval_minutes),
        "/F",
    )
    if result.returncode != 0:
        raise SchedulerError(result.stderr.strip() or result.stdout.strip())

is_installed()

Return True if the ChicoSync task exists in Task Scheduler.

Source code in chico/schedulers/windows.py
def is_installed() -> bool:
    """Return ``True`` if the ChicoSync task exists in Task Scheduler."""
    return _run("/Query", "/TN", TASK_NAME).returncode == 0

query()

Return key fields from the ChicoSync task, or None if not installed.

Parses the schtasks /Query /FO LIST /V output into a dict. Only the fields listed in :data:_STATUS_FIELDS are included.

Source code in chico/schedulers/windows.py
def query() -> dict[str, str] | None:
    """Return key fields from the ChicoSync task, or ``None`` if not installed.

    Parses the ``schtasks /Query /FO LIST /V`` output into a dict. Only the
    fields listed in :data:`_STATUS_FIELDS` are included.
    """
    result = _run("/Query", "/TN", TASK_NAME, "/FO", "LIST", "/V")
    if result.returncode != 0:
        return None

    data: dict[str, str] = {}
    for line in result.stdout.splitlines():
        match = re.match(r"^(.+?):\s{2,}(.*)$", line)
        if match:
            key = match.group(1).strip()
            if key in _STATUS_FIELDS:
                data[key] = match.group(2).strip()
    return data

uninstall()

Delete the ChicoSync scheduled task.

Raises:

Type Description
SchedulerError

If schtasks exits with a non-zero return code.

Source code in chico/schedulers/windows.py
def uninstall() -> None:
    """Delete the ChicoSync scheduled task.

    Raises
    ------
    SchedulerError
        If ``schtasks`` exits with a non-zero return code.
    """
    result = _run("/Delete", "/TN", TASK_NAME, "/F")
    if result.returncode != 0:
        raise SchedulerError(result.stderr.strip() or result.stdout.strip())