Commit 9ec16d97 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Add an iCalendar printer.

This command is similar to the 'ls' subcommand, except that it prints
the selected todo items as an iCalendar file. This can be read by other
calendaring applications.
parent 6f4de340
...@@ -8,6 +8,9 @@ setup( ...@@ -8,6 +8,9 @@ setup(
author = "Bram Schoenmakers", author = "Bram Schoenmakers",
author_email = "me@bramschoenmakers.nl", author_email = "me@bramschoenmakers.nl",
url = "https://github.com/bram85/topydo", url = "https://github.com/bram85/topydo",
extras_require = {
'ical': ['icalendar'],
},
entry_points= { entry_points= {
'console_scripts': ['topydo = topydo.cli.Main:main'], 'console_scripts': ['topydo = topydo.cli.Main:main'],
}, },
......
...@@ -41,6 +41,7 @@ Available commands: ...@@ -41,6 +41,7 @@ Available commands:
* dep * dep
* do * do
* edit * edit
* ical
* ls * ls
* listcon (lscon) * listcon (lscon)
* listprojects (lsprj) * listprojects (lsprj)
...@@ -97,6 +98,7 @@ from topydo.lib.DepCommand import DepCommand ...@@ -97,6 +98,7 @@ from topydo.lib.DepCommand import DepCommand
from topydo.lib.DepriCommand import DepriCommand from topydo.lib.DepriCommand import DepriCommand
from topydo.lib.DoCommand import DoCommand from topydo.lib.DoCommand import DoCommand
from topydo.lib.EditCommand import EditCommand from topydo.lib.EditCommand import EditCommand
from topydo.lib.IcalCommand import IcalCommand
from topydo.lib.ListCommand import ListCommand from topydo.lib.ListCommand import ListCommand
from topydo.lib.ListContextCommand import ListContextCommand from topydo.lib.ListContextCommand import ListContextCommand
from topydo.lib.ListProjectCommand import ListProjectCommand from topydo.lib.ListProjectCommand import ListProjectCommand
...@@ -118,6 +120,7 @@ SUBCOMMAND_MAP = { ...@@ -118,6 +120,7 @@ SUBCOMMAND_MAP = {
'depri': DepriCommand, 'depri': DepriCommand,
'do': DoCommand, 'do': DoCommand,
'edit': EditCommand, 'edit': EditCommand,
'ical': IcalCommand,
'ls': ListCommand, 'ls': ListCommand,
'lscon': ListContextCommand, 'lscon': ListContextCommand,
'listcon': ListContextCommand, 'listcon': ListContextCommand,
......
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2015 Bram Schoenmakers <me@bramschoenmakers.nl>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Implements a subcommand that outputs an iCalendar file.
"""
from topydo.lib.IcalPrinter import IcalPrinter
from topydo.lib.ListCommand import ListCommand
class IcalCommand(ListCommand):
def __init__(self, p_args, p_todolist,
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(IcalCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.printer = IcalPrinter(p_todolist)
def _print(self):
self.out(str(self._view()))
def execute(self):
try:
import icalendar as _
except ImportError:
self.error("icalendar package is not installed.")
return False
return super(IcalCommand, self).execute()
def usage(self):
return """Synopsis: ical [-x] [expression]"""
def help(self):
return """\
Similar to the 'ls' subcommand, except that the todos are printed in iCalendar
format (RFC 2445) that can be imported by other calendar applications.
By default prints the active todo items, possibly filtered by the given
expression.
For the supported options, please refer to the help text of 'ls'
(topydo help ls).
While specifying the sort order is supported (-s flag), like in 'ls', this is
not meaningful in the context of an iCalendar file.
Note: be aware that this is not necessarily a read-only operation. This
subcommand may add ical tags to the printed todo items containing a unique ID.
Completed todo items may be archived.
Note: topydo does not support reading iCal files, this is merely a dump.
Changes made with other iCalendar enabled applications will not be processed.
Suggested usage is to use the output as a read-only calendar.
"""
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2015 Bram Schoenmakers <me@bramschoenmakers.nl>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Provides a printer that transforms a list of Todo items to an iCalendar
file according to RFC 2445.
"""
try:
import icalendar as ical
ICAL_PRESENT = True
except ImportError:
ICAL_PRESENT = False
from datetime import datetime, time
import random
import string
from topydo.lib.PrettyPrinter import Printer
def _convert_priority(p_priority):
"""
Converts todo.txt priority to an iCalendar priority (RFC 2445).
Priority A gets priority 1, priority B gets priority 5 and priority C-F get
priorities 6-9. This scheme makes sure that clients that use "high",
"medium" and "low" show the correct priority.
"""
result = 0
prio_map = {
'A': 1,
'B': 5,
'C': 6,
'D': 7,
'E': 8,
'F': 9,
}
try:
result = prio_map[p_priority]
except KeyError:
if p_priority:
# todos with no priority have priority None, and result of this
# function will be 0. For all other letters, return 9 (lowest
# priority in RFC 2445).
result = 9
return result
class IcalPrinter(Printer):
"""
A printer that converts a list of Todo items to a string in iCalendar
format (RFC 2445).
https://www.rfc-editor.org/rfc/rfc2445.txt
"""
def __init__(self, p_todolist):
super(IcalPrinter, self).__init__()
self.todolist = p_todolist
def print_todo(self, p_todo):
return self._convert_todo(p_todo).to_ical() if ICAL_PRESENT else ""
def print_list(self, p_todos):
result = ""
if ICAL_PRESENT:
cal = ical.Calendar()
cal.add('prodid', '-//bramschoenmakers.nl//topydo//')
cal.add('version', '2.0')
for todo in p_todos:
cal.add_component(self._convert_todo(todo))
result = cal.to_ical()
return result
def _convert_todo(self, p_todo):
""" Converts a Todo instance (Topydo) to an icalendar Todo instance. """
def _get_uid(p_todo):
"""
Gets a unique ID from a todo item, stored by the ical tag. If the
tag is not present, a random value is assigned to it and returned.
"""
def generate_uid(p_length=4):
"""
Generates a random string of the given length, used as
identifier.
"""
return ''.join(
random.choice(string.ascii_letters + string.digits)
for i in xrange(p_length))
uid = p_todo.tag_value('ical')
if not uid:
uid = generate_uid()
p_todo.set_tag('ical', uid)
self.todolist.set_dirty()
return uid
result = ical.Todo()
# this should be called first, it may set the ical: tag and therefore
# change the source() output.
result['uid'] = _get_uid(p_todo)
result['summary'] = ical.vText(p_todo.text())
result['description'] = ical.vText(p_todo.source())
result.add('priority', _convert_priority(p_todo.priority()))
start = p_todo.start_date()
if start:
result.add('dtstart', start)
due = p_todo.due_date()
if due:
result.add('due', due)
created = p_todo.creation_date()
if created:
result.add('created', created)
completed = p_todo.completion_date()
if completed:
completed = datetime.combine(completed, time(0, 0))
result.add('completed', completed)
return result
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment