NextCloud tasks API

Python library for managing todo lists on a NextCloud instance with the default Tasks app. Provides fully async access to the WebDAV API for managing iCal calendars.

The default NextCloud Tasks App allows to manage task lists in calendars, which can be synced across devices via iCal “todos”. As the corresponding WebGUI can be inconvenient for some use-cases or might not be exposed, this NextCloud WebDAV API library allows to use the core functionality also in other contexts or for automation.

This is the successor and async reimplementation of the initial API project, which comes with a bundled CLI and should be considered legacy by now.

Based on this library, a convenient and responsive terminal client for todo lists and tasks is provided by the console TUI project.

Quick Reference

An API instance can be obtained by the corresponding factory as convenience wrapper. As quickstart, the following minimal but complete and functional example creates a new task and prints all tasks for all task lists found:

#!/usr/bin/env python3

import sys
import time
import asyncio
from nextcloud_tasks_api import NextcloudTasksApiFactory, NextcloudTasksApi
from nextcloud_tasks_api.ical import Task

async def _main() -> int:
    factory: NextcloudTasksApiFactory = NextcloudTasksApiFactory("https://my.nextcloud.example/")
    nextcloud: NextcloudTasksApi = await factory.create("username", "password")

    async with nextcloud as api:  # enter context to create a session
        async for task_list in api.get_lists():  # get all task lists belonging to the authenticated user
            print(f"{task_list.name}:")
            async for task_file in api.get_list(task_list):  # get all tasks of the task list
                task = Task(task_file.content)  # parse returned iCal task content
                print(f" {'✓' if task.completed is not None else '✗'} {task.summary}")

            if task_list.name == "My Tasks":  # add new (already completed) task to this task list
                new_task = Task()  # empty iCal VTODO stub
                new_task.summary = "Did the thing"
                new_task.completed = time.time()
                await api.create_task(task_list, new_task.to_string())
    return 0

def main() -> int:
    return asyncio.run(_main())

if __name__ == "__main__":
    sys.exit(main())

This assumes the nextcloud_tasks_api package is installed globally, per user, in the current virtual environment, or via pipenv.

API Configuration

base_url: str
Root URL of the NextCloud instance. Requests will be made to the remote.php/dav/ API endpoint below.
verify_ssl: bool = True
Disable to ignore certificate errors.
limit: int = 0
Limiting semaphore on pending requests. When enabled, can avoid database is locked errors on some installations under high load.
timeout: Optional[float] = None
Overall timeout for each request.
username: str
Username for HTTP Basic authentication.
password: str
Password to login with. Using an App Password instead of the main account’s password should be considered and is needed when 2FA is enabled.

API Endpoints

async def list_user_principal() -> AsyncIterator[str]:
    """Query current user principal endpoints. Useful to validate endpoint and authentication settings."""
async def get_lists() -> AsyncIterator[TaskList]:
    """Find all available task lists."""
async def get_list(task_list: TaskList, completed: Optional[bool] = None) -> AsyncIterator[TaskFile]:
    """Get all tasks of a task list, optionally filter remotely by completion state."""
async def create_list(name: str, color: str = "#0082c9", filename: Optional[str] = None) -> TaskList:
    """Create a new task list with the given displayname and (unverified) filename."""
async def update_list(task_list: TaskList) -> None:
    """Update a task list with its updated handle."""
async def delete_list(task_list: TaskList) -> None:
    """Delete the given task list."""
async def create_task(task_list: TaskList, task: str, filename: Optional[UUID] = None) -> TaskFile:
    """Create a new task in the task list with the given iCal content."""
async def update_task(task: TaskFile) -> TaskFile:
    """Update a task with new content."""
async def delete_task(task: TaskFile) -> None:
    """Delete a task. This does not recursively delete subtasks."""

iCal Task Parser

The API itself is only directly concerned with NextCloud-specific XML/WebDAV operations and transparently operates on unparsed content. So any parsing approach can be used on the returned vCalendar/vEvent/iCal strings.

However, a simple iCal parser and factory as well as a Task class is readily included that can optionally be used for working with typical VTODO properties. No additional requirements should thus be needed, but more elaborate libraries with todo support already exist on PyPI, for example ical or iCal-library.

While all iCal VTODO entries can be directly modified by the key/parameter/value datastructure, there are convenience task properties and setters for:

Note that individual parameters are not parsed and taken into account by this implementation. This for example also applies to custom timezones, such that the timestamps are assumed to be in UTC.

Installation

The most easy way to (un-)install the nextcloud-tasks-api package is via pip. If not already present, a corresponding system package such as python3-pip should exist.

pip install .[lxml]
pip uninstall nextcloud-tasks-api

These commands are also the ones used by make install and make uninstall and include the optional lxml requirement as extra for improved parsing performance. The only hard requirement implicitly installed is aiohttp.

For trying out or local development, a virtual environment can be used. Wrapped by the Makefile, a make check will invoke type checker and linter.

Code & Download