CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-caldav

CalDAV (RFC4791) client library for Python with comprehensive calendar server interaction capabilities

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

task-management.mddocs/

Task Management

Comprehensive todo/task management functionality with support for due dates, completion tracking, priority management, and task hierarchies using CalDAV VTODO components.

Capabilities

Todo Class

Represents CalDAV todos/tasks (VTODO components) with specialized methods for task-specific operations including completion tracking and due date management.

class Todo(CalendarObjectResource):
    def get_due(self):
        """
        Get todo due date/time.
        
        Returns:
        datetime or date: Todo due date/time, or None if not set
        """
    
    def get_dtstart(self):
        """
        Get todo start date/time.
        
        Returns:
        datetime or date: Todo start date/time, or None if not set
        """
    
    def get_duration(self):
        """
        Get todo duration.
        
        Returns:
        timedelta: Todo duration, or None if not set
        """
    
    def set_due(self, due):
        """
        Set todo due date/time.
        
        Parameters:
        - due: datetime or date, new due date/time
        """
    
    def set_dtstart(self, dtstart):
        """
        Set todo start date/time.
        
        Parameters:
        - dtstart: datetime or date, new start date/time
        """
    
    def set_duration(self, duration):
        """
        Set todo duration.
        
        Parameters:
        - duration: timedelta, task duration
        """
    
    def complete(self, completion_timestamp=None, handle_rrule=True):
        """
        Mark todo as completed.
        
        Parameters:
        - completion_timestamp: datetime, completion time (default: now)
        - handle_rrule: bool, handle recurring todos by creating next occurrence
        
        Returns:
        Todo: Next occurrence if recurring, or None
        """

Usage Examples:

import caldav
from datetime import datetime, timedelta, timezone

# Get existing todos
calendar = principal.calendars()[0]
todos = calendar.todos()

if todos:
    todo = todos[0]
    
    # Get todo information
    summary = todo.icalendar_component.get('SUMMARY', 'No title')
    due_date = todo.get_due()
    start_date = todo.get_dtstart()
    status = todo.icalendar_component.get('STATUS', 'No status')
    
    print(f"Todo: {summary}")
    print(f"Due: {due_date}")
    print(f"Status: {status}")
    
    # Modify todo timing
    new_due = datetime(2025, 9, 30, 17, 0, tzinfo=timezone.utc)
    todo.set_due(new_due)
    todo.set_dtstart(datetime.now(timezone.utc))
    
    # Mark as completed
    if status != 'COMPLETED':
        next_occurrence = todo.complete()
        if next_occurrence:
            print(f"Created next occurrence: {next_occurrence.id}")
        else:
            print("Todo marked as completed")

Todo Creation

Create new todos with comprehensive VTODO support including all standard properties and task-specific features.

# Todo creation through calendar.save_todo() - see calendar-management.md
# Additional todo-specific creation patterns:

def create_simple_todo(summary, due_date=None, priority=None, description=None):
    """
    Helper function to create simple todo iCalendar data.
    
    Parameters:
    - summary: str, todo title/summary
    - due_date: datetime, optional due date
    - priority: int, priority level (1-9, 1=highest, 9=lowest)
    - description: str, optional todo description
    
    Returns:
    str: iCalendar data for the todo
    """

Usage Examples:

from datetime import datetime, timezone
import uuid

# Create a simple todo
def create_task(title, due_date=None, priority=5, description=None):
    task_uid = f"{uuid.uuid4()}@example.com"
    
    ical_data = f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My Task App//My Task App//EN
BEGIN:VTODO
UID:{task_uid}
SUMMARY:{title}
STATUS:NEEDS-ACTION
PRIORITY:{priority}
"""
    
    if due_date:
        ical_data += f"DUE:{due_date.strftime('%Y%m%dT%H%M%SZ')}\n"
    if description:
        ical_data += f"DESCRIPTION:{description}\n"
    
    ical_data += f"""DTSTAMP:{datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ')}
END:VTODO
END:VCALENDAR"""
    
    return ical_data

# Create and save a todo
task_due = datetime(2025, 10, 1, 17, 0, tzinfo=timezone.utc)
task_ical = create_task(
    title="Complete project documentation",
    due_date=task_due,
    priority=2,  # High priority
    description="Finish writing user guide and API documentation"
)

todo = calendar.save_todo(task_ical)
print(f"Created todo: {todo.id}")

# Create recurring todo
recurring_todo_ical = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My App//My App//EN
BEGIN:VTODO
UID:weekly-report@example.com
SUMMARY:Submit weekly status report
DESCRIPTION:Prepare and submit weekly project status report
DUE:20250919T170000Z
STATUS:NEEDS-ACTION
PRIORITY:3
RRULE:FREQ=WEEKLY;BYDAY=FR;COUNT=12
END:VTODO
END:VCALENDAR"""

recurring_todo = calendar.save_todo(recurring_todo_ical)

# Create todo with subtasks (using RELATED-TO property)
parent_todo_ical = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My App//My App//EN
BEGIN:VTODO
UID:project-launch@example.com
SUMMARY:Launch new product
DESCRIPTION:Complete all tasks required for product launch
DUE:20251215T170000Z
STATUS:NEEDS-ACTION
PRIORITY:1
END:VTODO
END:VCALENDAR"""

parent_todo = calendar.save_todo(parent_todo_ical)

# Create subtask
subtask_ical = f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My App//My App//EN
BEGIN:VTODO
UID:marketing-materials@example.com
SUMMARY:Create marketing materials
DESCRIPTION:Design and create marketing collateral
DUE:20251201T170000Z
STATUS:NEEDS-ACTION
PRIORITY:2
RELATED-TO;RELTYPE=PARENT:{parent_todo.id}
END:VTODO
END:VCALENDAR"""

subtask = calendar.save_todo(subtask_ical)

Todo Status Management

Comprehensive status tracking and workflow management for todos with support for different completion states.

# Todo status values (accessed via icalendar_component['STATUS'])
TODO_STATUS = {
    "NEEDS-ACTION": "Task needs to be completed",
    "COMPLETED": "Task has been completed", 
    "IN-PROCESS": "Task is currently being worked on",
    "CANCELLED": "Task has been cancelled"
}

# Todo priority levels (accessed via icalendar_component['PRIORITY'])
TODO_PRIORITY = {
    0: "Undefined priority",
    1: "Highest priority",
    2: "High priority",
    3: "High priority", 
    4: "Medium-high priority",
    5: "Medium priority (default)",
    6: "Medium-low priority",
    7: "Low priority",
    8: "Low priority",
    9: "Lowest priority"
}

Usage Examples:

# Manage todo status
todo = calendar.todo_by_uid("project-task@example.com")
if todo:
    component = todo.icalendar_component
    
    # Check current status
    current_status = component.get('STATUS', 'NEEDS-ACTION')
    print(f"Current status: {current_status}")
    
    # Start working on the task
    component['STATUS'] = 'IN-PROCESS'
    component['PERCENT-COMPLETE'] = 25  # 25% complete
    todo.save()
    
    # Update progress
    component['PERCENT-COMPLETE'] = 75
    todo.save()
    
    # Complete the task
    todo.complete()  # This sets STATUS=COMPLETED and COMPLETED timestamp

# Filter todos by status
pending_todos = calendar.search(
    comp_filter="VTODO",
    prop_filter={"STATUS": "NEEDS-ACTION"}
)

in_progress_todos = calendar.search(
    comp_filter="VTODO", 
    prop_filter={"STATUS": "IN-PROCESS"}
)

completed_todos = calendar.search(
    comp_filter="VTODO",
    prop_filter={"STATUS": "COMPLETED"}
)

print(f"Pending: {len(pending_todos)}, In Progress: {len(in_progress_todos)}, Completed: {len(completed_todos)}")

Todo Hierarchy and Dependencies

Manage task hierarchies and dependencies using RELATED-TO properties for project organization and workflow management.

def get_relatives(self, field_filter=None, include_self=False):
    """
    Get related todos (parent/child relationships).
    
    Parameters:
    - field_filter: str, filter by relation type ('PARENT', 'CHILD', 'SIBLING')
    - include_self: bool, include this todo in results
    
    Returns:
    list[CalendarObjectResource]: Related todos
    """

Usage Examples:

# Create project with subtasks
project_ical = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My App//My App//EN
BEGIN:VTODO
UID:website-redesign@example.com
SUMMARY:Website Redesign Project
DESCRIPTION:Complete website redesign and launch
DUE:20251231T170000Z
STATUS:NEEDS-ACTION
PRIORITY:1
END:VTODO
END:VCALENDAR"""

project = calendar.save_todo(project_ical)

# Create subtasks with parent relationship
subtasks = [
    ("Design mockups", "Create visual designs and mockups", "20251115T170000Z"),
    ("Frontend development", "Implement frontend based on designs", "20251201T170000Z"),
    ("Backend integration", "Connect frontend to existing backend", "20251215T170000Z"),
    ("Testing and QA", "Test all functionality and fix bugs", "20251220T170000Z")
]

created_subtasks = []
for i, (summary, description, due) in enumerate(subtasks):
    subtask_uid = f"website-subtask-{i+1}@example.com"
    
    subtask_ical = f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My App//My App//EN
BEGIN:VTODO
UID:{subtask_uid}
SUMMARY:{summary}
DESCRIPTION:{description}
DUE:{due}
STATUS:NEEDS-ACTION
PRIORITY:2
RELATED-TO;RELTYPE=PARENT:{project.id}
END:VTODO
END:VCALENDAR"""
    
    subtask = calendar.save_todo(subtask_ical)
    created_subtasks.append(subtask)

# Find all subtasks of the project
project_subtasks = project.get_relatives(field_filter="CHILD")
print(f"Project has {len(project_subtasks)} subtasks")

# Create dependency between subtasks (frontend depends on design)
design_task = created_subtasks[0]
frontend_task = created_subtasks[1]

# Add dependency relationship
frontend_component = frontend_task.icalendar_component
frontend_component.add('RELATED-TO', design_task.id)
frontend_component['RELATED-TO'].params['RELTYPE'] = 'DEPENDS-ON'
frontend_task.save()

print(f"Frontend task now depends on: {design_task.id}")

Todo Queries and Filtering

Advanced todo querying with status filters, due date ranges, and priority-based searches.

# Common todo search patterns using calendar.search() - see calendar-management.md

def find_overdue_todos(calendar):
    """Find todos past their due date."""
    from datetime import datetime
    now = datetime.now()
    
    todos = calendar.search(comp_filter="VTODO")
    overdue = []
    
    for todo in todos:
        due_date = todo.get_due()
        status = todo.icalendar_component.get('STATUS', 'NEEDS-ACTION')
        
        if due_date and due_date < now and status != 'COMPLETED':
            overdue.append(todo)
    
    return overdue

def find_high_priority_todos(calendar):
    """Find high priority todos."""
    return calendar.search(
        comp_filter="VTODO",
        prop_filter={"PRIORITY": "1"}
    ) + calendar.search(
        comp_filter="VTODO", 
        prop_filter={"PRIORITY": "2"}
    )

def find_todos_due_this_week(calendar):
    """Find todos due in the next 7 days."""
    from datetime import datetime, timedelta
    
    start = datetime.now()
    end = start + timedelta(days=7)
    
    todos = calendar.search(comp_filter="VTODO")
    due_this_week = []
    
    for todo in todos:
        due_date = todo.get_due()
        status = todo.icalendar_component.get('STATUS', 'NEEDS-ACTION')
        
        if due_date and start <= due_date <= end and status != 'COMPLETED':
            due_this_week.append(todo)
    
    return due_this_week

Usage Examples:

# Find todos by various criteria
overdue = find_overdue_todos(calendar)
print(f"Overdue todos: {len(overdue)}")

high_priority = find_high_priority_todos(calendar)
print(f"High priority todos: {len(high_priority)}")

due_soon = find_todos_due_this_week(calendar)
print(f"Due this week: {len(due_soon)}")

# Search by text in summary or description
project_todos = calendar.search(
    comp_filter="VTODO",
    text_match="website"
)

# Find todos by specific status
active_todos = calendar.search(
    comp_filter="VTODO",
    prop_filter={"STATUS": "IN-PROCESS"}
)

# Complex status filtering
incomplete_todos = []
for status in ["NEEDS-ACTION", "IN-PROCESS"]:
    todos = calendar.search(
        comp_filter="VTODO",
        prop_filter={"STATUS": status}
    )
    incomplete_todos.extend(todos)

print(f"Total incomplete todos: {len(incomplete_todos)}")

Recurring Todos

Handle recurring todos with automatic creation of next occurrences upon completion.

# Recurring todos use the same RRULE syntax as events
# When completed with handle_rrule=True, a new occurrence is automatically created

RECURRING_TODO_PATTERNS = {
    "daily": "FREQ=DAILY",
    "weekdays": "FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR", 
    "weekly": "FREQ=WEEKLY",
    "monthly": "FREQ=MONTHLY",
    "yearly": "FREQ=YEARLY"
}

Usage Examples:

# Create daily recurring todo
daily_standup_ical = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My App//My App//EN
BEGIN:VTODO
UID:daily-standup-prep@example.com
SUMMARY:Prepare for daily standup
DESCRIPTION:Review progress and prepare standup updates
DUE:20250915T090000Z
STATUS:NEEDS-ACTION
PRIORITY:3
RRULE:FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR;COUNT=50
END:VTODO
END:VCALENDAR"""

recurring_todo = calendar.save_todo(daily_standup_ical)

# Complete the recurring todo - this creates the next occurrence
next_occurrence = recurring_todo.complete(handle_rrule=True)
if next_occurrence:
    print(f"Completed today's standup prep, created tomorrow's: {next_occurrence.id}")

# Create monthly recurring todo
monthly_report_ical = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My App//My App//EN
BEGIN:VTODO
UID:monthly-report@example.com
SUMMARY:Submit monthly progress report
DESCRIPTION:Compile and submit monthly team progress report
DUE:20250930T170000Z
STATUS:NEEDS-ACTION
PRIORITY:2
RRULE:FREQ=MONTHLY;BYMONTHDAY=-1
END:VTODO
END:VCALENDAR"""

monthly_todo = calendar.save_todo(monthly_report_ical)

Todo Properties

# Common todo properties that can be accessed via icalendar_component
TODO_PROPERTIES = {
    "SUMMARY": "str",              # Todo title/summary
    "DESCRIPTION": "str",          # Todo description  
    "DUE": "datetime",            # Due date/time
    "DTSTART": "datetime",        # Start date/time
    "DURATION": "timedelta",      # Duration
    "STATUS": "str",              # NEEDS-ACTION, COMPLETED, IN-PROCESS, CANCELLED
    "PRIORITY": "int",            # Priority (0-9, 0=undefined, 1=highest, 9=lowest)
    "PERCENT-COMPLETE": "int",    # Completion percentage (0-100)
    "COMPLETED": "datetime",      # Completion timestamp (set by complete())
    "CLASS": "str",               # PUBLIC, PRIVATE, CONFIDENTIAL
    "CATEGORIES": "list[str]",    # Todo categories/tags
    "RELATED-TO": "str",          # Related todo UID
    "RRULE": "str",              # Recurrence rule
}

Install with Tessl CLI

npx tessl i tessl/pypi-caldav

docs

calendar-management.md

client-auth.md

event-operations.md

index.md

journal-freebusy.md

principal-calendar.md

task-management.md

tile.json