diff --git a/radicale.py b/radicale.py index ae40770..b94292c 100755 --- a/radicale.py +++ b/radicale.py @@ -2,7 +2,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,6 +25,12 @@ # TODO: Magage command-line options # TODO: Forget twisted? +""" +Radicale Server entry point. + +Launch the Radicale Serve according to the configuration. +""" + import sys from twisted.web import server from twisted.internet import reactor @@ -31,18 +39,14 @@ from twisted.python import log import radicale class ServerContextFactory(object): - """ - SSL context factory - """ - def getContext(self): - """ - Get SSL context for the HTTP server - """ + """SSL context factory.""" + def get_context(self): + """Get SSL context for the HTTP server.""" from OpenSSL import SSL - ctx = SSL.Context(SSL.SSLv23_METHOD) - ctx.use_certificate_file(radicale.config.get("server", "certificate")) - ctx.use_privatekey_file(radicale.config.get("server", "privatekey")) - return ctx + context = SSL.Context(SSL.SSLv23_METHOD) + context.use_certificate_file(radicale.config.get("server", "certificate")) + context.use_privatekey_file(radicale.config.get("server", "privatekey")) + return context log.startLogging(sys.stdout) #log.startLogging(open(radicale.config.get("server", "log"), "w")) diff --git a/radicale/__init__.py b/radicale/__init__.py index 6057721..81e4bdc 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,16 +19,15 @@ # along with Radicale. If not, see . # TODO: Manage errors (see xmlutils) +# TODO: Forget twisted? from twisted.web.resource import Resource from twisted.web import http import posixpath import config - import support import acl - import xmlutils import calendar @@ -34,112 +35,88 @@ _users = acl.users() _calendars = support.calendars() class CalendarResource(Resource): - """ - Twisted resource for requests at calendar depth (/user/calendar) - """ + """Twisted resource for requests at calendar depth (/user/calendar).""" + # Tell twisted this is a leaf for requests isLeaf = True def __init__(self, user, cal): - """ - Initialize resource creating a calendar object corresponding - to the stocked calendar named user/cal + """Initialize by creating a calendar object. + + The calendar object corresponds to the stocked calendar named + ``user``/``cal``. """ Resource.__init__(self) self.calendar = calendar.Calendar(user, cal) def render_DELETE(self, request): - """ - Manage DELETE requests - """ + """Manage DELETE ``request``.""" obj = request.getHeader("if-match") answer = xmlutils.delete(obj, self.calendar, str(request.URLPath())) request.setResponseCode(http.NO_CONTENT) return answer def render_OPTIONS(self, request): - """ - Manage OPTIONS requests - """ + """Manage OPTIONS ``request``.""" request.setHeader("Allow", "DELETE, OPTIONS, PROPFIND, PUT, REPORT") request.setHeader("DAV", "1, calendar-access") request.setResponseCode(http.OK) return "" def render_PROPFIND(self, request): - """ - Manage PROPFIND requests - """ - xmlRequest = request.content.read() - answer = xmlutils.propfind(xmlRequest, self.calendar, str(request.URLPath())) + """Manage PROPFIND ``request``.""" + xml_request = request.content.read() + answer = xmlutils.propfind(xml_request, self.calendar, str(request.URLPath())) request.setResponseCode(http.MULTI_STATUS) return answer def render_PUT(self, request): - """ - Manage PUT requests - """ + """Manage PUT ``request``.""" # TODO: Improve charset detection contentType = request.getHeader("content-type") if contentType and "charset=" in contentType: charset = contentType.split("charset=")[1].strip() else: charset = config.get("encoding", "request") - icalRequest = unicode(request.content.read(), charset) + ical_request = request.content.read().decode(charset) obj = request.getHeader("if-match") - xmlutils.put(icalRequest, self.calendar, str(request.URLPath()), obj) + xmlutils.put(ical_request, self.calendar, str(request.URLPath()), obj) request.setResponseCode(http.CREATED) return "" def render_REPORT(self, request): - """ - Manage REPORT requests - """ - xmlRequest = request.content.read() - answer = xmlutils.report(xmlRequest, self.calendar, str(request.URLPath())) + """Manage REPORT ``request``.""" + xml_request = request.content.read() + answer = xmlutils.report(xml_request, self.calendar, str(request.URLPath())) request.setResponseCode(http.MULTI_STATUS) return answer class UserResource(Resource): - """ - Twisted resource for requests at user depth (/user) - """ + """Twisted resource for requests at user depth (/user).""" def __init__(self, user): - """ - Initialize resource by connecting children requests to - the user calendars resources - """ + """Initialize by connecting requests to ``user`` calendars resources.""" Resource.__init__(self) for cal in _calendars: if cal.startswith("%s%s"%(user, posixpath.sep)): - calName = cal.split(posixpath.sep)[1] - self.putChild(calName, CalendarResource(user, cal)) + cal_name = cal.split(posixpath.sep)[1] + self.putChild(cal_name, CalendarResource(user, cal)) def getChild(self, cal, request): - """ - Get calendar resource if user exists - """ + """Get calendar resource if ``cal`` exists.""" if cal in _calendars: return Resource.getChild(self, cal, request) else: return self class HttpResource(Resource): - """ - Twisted resource for requests at root depth (/) - """ + """Twisted resource for requests at root depth (/).""" def __init__(self): - """ - Initialize resource by connecting children requests to - the users resources - """ + """Initialize by connecting requests to the users resources.""" Resource.__init__(self) for user in _users: self.putChild(user, UserResource(user)) def getChild(self, user, request): - """ - Get user resource if user exists - """ + """Get user resource if ``user`` exists.""" if user in _users: return Resource.getChild(self, user, request) else: diff --git a/radicale/acl/__init__.py b/radicale/acl/__init__.py index f7a0168..75b3052 100644 --- a/radicale/acl/__init__.py +++ b/radicale/acl/__init__.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,6 +18,13 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +""" +Users and rights management. + +This module loads a list of users with access rights, according to the acl +configuration. +""" + from .. import config _acl = __import__(config.get("acl", "type"), locals(), globals()) diff --git a/radicale/acl/fake.py b/radicale/acl/fake.py index 050b8af..e37cdc0 100644 --- a/radicale/acl/fake.py +++ b/radicale/acl/fake.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,10 +18,14 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +""" +Fake ACL. + +Just load the default user set in configuration, with no rights management. +""" + from .. import config def users(): - """ - Get the List of all Users - """ - return [config.get("acl", "defaultUser")] + """Get the list of all users.""" + return [config.get("acl", "user")] diff --git a/radicale/acl/htpasswd.py b/radicale/acl/htpasswd.py index 2c5e835..f764776 100644 --- a/radicale/acl/htpasswd.py +++ b/radicale/acl/htpasswd.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,10 +18,17 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +""" +Htpasswd ACL. + +Load the list of users according to the htpasswd configuration. +""" + +# TODO: Manage rights + from .. import config def users(): - """ - Get the List of all Users - """ - return [line.split(":")[0] for line in open(config.get("acl", "filename")).readlines()] + """Get the list of all users.""" + return [line.split(":")[0] for line + in open(config.get("acl", "filename")).readlines()] diff --git a/radicale/calendar.py b/radicale/calendar.py index 942fc58..0b1c0f9 100644 --- a/radicale/calendar.py +++ b/radicale/calendar.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,73 +18,68 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . -# TODO: Manage inheritance for classes +""" +Radicale calendar classes. -from time import time +Define the main classes of a calendar as seen from the server. +""" import support +hash_tag = lambda vcalendar: str(hash(vcalendar)) + class Calendar(object): - """ - Internal Calendar Class - """ + """Internal calendar class.""" def __init__(self, user, cal): - # TODO: Use properties from the calendar + """Initialize the calendar with ``cal`` and ``user`` parameters.""" + # TODO: Use properties from the calendar configuration self.encoding = "utf-8" self.owner = "lize" self.user = user self.cal = cal self.version = "2.0" - self.ctag = str(hash(self.vcalendar())) + self.ctag = hash_tag(self.vcalendar()) def append(self, vcalendar): - """ - Append vcalendar - """ - self.ctag = str(hash(self.vcalendar())) + """Append vcalendar to the calendar.""" + self.ctag = hash_tag(self.vcalendar()) support.append(self.cal, vcalendar) def remove(self, uid): - """ - Remove Object Named uid - """ - self.ctag = str(hash(self.vcalendar())) + """Remove object named ``uid`` from the calendar.""" + self.ctag = hash_tag(self.vcalendar()) support.remove(self.cal, uid) def replace(self, uid, vcalendar): - """ - Replace Objet Named uid by vcalendar - """ - self.ctag = str(hash(self.vcalendar())) + """Replace objet named ``uid`` by ``vcalendar`` in the calendar.""" + self.ctag = hash_tag(self.vcalendar()) support.remove(self.cal, uid) support.append(self.cal, vcalendar) def vcalendar(self): + """Return unicode calendar from the calendar.""" return unicode(support.read(self.cal), self.encoding) class Event(object): - """ - Internal Event Class - """ - # TODO: Fix the behaviour if no UID is given + """Internal event class.""" def __init__(self, vcalendar): + """Initialize event from ``vcalendar``.""" self.text = vcalendar def etag(self): - return str(hash(self.text)) + """Return etag from event.""" + return hash_tag(self.text) class Header(object): - """ - Internal Headers Class - """ + """Internal header class.""" def __init__(self, vcalendar): + """Initialize header from ``vcalendar``.""" self.text = vcalendar class Timezone(object): - """ - Internal Timezone Class - """ + """Internal timezone class.""" def __init__(self, vcalendar): + """Initialize timezone from ``vcalendar``.""" lines = vcalendar.splitlines() for line in lines: if line.startswith("TZID:"): @@ -92,12 +89,11 @@ class Timezone(object): self.text = vcalendar class Todo(object): - """ - Internal Todo Class - """ - # TODO: Fix the behaviour if no UID is given + """Internal todo class.""" def __init__(self, vcalendar): + """Initialize todo from ``vcalendar``.""" self.text = vcalendar def etag(self): - return str(hash(self.text)) + """Return etag from todo.""" + return hash_tag(self.text) diff --git a/radicale/config.py b/radicale/config.py index 98a0098..1321a6e 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,9 +18,14 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +""" +Radicale configuration module. + +Give a configparser-like interface to read and write configuration. +""" + from ConfigParser import RawConfigParser as ConfigParser -# Default functions _config = ConfigParser() get = _config.get set = _config.set @@ -28,7 +35,6 @@ getfloat = _config.getfloat options = _config.options items = _config.items -# Default config _initial = { "server": { "type": "http", @@ -53,20 +59,19 @@ _initial = { "acl": { "type": "fake", "filename": "/etc/radicale/users", - "defaultUser": "radicale", + "user": "radicale", }, "support": { "type": "plain", "folder": "~/.config/radicale", - "defaultCalendar": "radicale/calendar", + "calendar": "radicale/calendar", }, } -# Set the default config for section, values in _initial.iteritems(): _config.add_section(section) for key, value in values.iteritems(): _config.set(section, key, value) -# Set the user config +# TODO: Use abstract filename for other platforms _config.read("/etc/radicale/config") diff --git a/radicale/ical.py b/radicale/ical.py index 46f6260..2f1e824 100644 --- a/radicale/ical.py +++ b/radicale/ical.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,16 +18,19 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +""" +iCal parsing functions. +""" + # TODO: Manage filters (see xmlutils) import calendar -def writeCalendar(headers=[calendar.Header("PRODID:-//The Radicale Team//NONSGML Radicale Server//EN"), - calendar.Header("VERSION:2.0")], +def write_calendar(headers=[ + calendar.Header("PRODID:-//Radicale//NONSGML Radicale Server//EN"), + calendar.Header("VERSION:2.0")], timezones=[], todos=[], events=[]): - """ - Create calendar from headers, timezones, todos, events - """ + """Create calendar from ``headers``, ``timezones``, ``todos``, ``events``.""" # TODO: Manage encoding and EOL cal = u"\n".join(( u"BEGIN:VCALENDAR", @@ -37,9 +42,7 @@ def writeCalendar(headers=[calendar.Header("PRODID:-//The Radicale Team//NONSGML return u"\n".join([line for line in cal.splitlines() if line]) def headers(vcalendar): - """ - Find Headers Items in vcalendar - """ + """Find Headers items in ``vcalendar``.""" headers = [] lines = vcalendar.splitlines() @@ -53,6 +56,10 @@ def headers(vcalendar): return headers def _parse(vcalendar, tag, obj): + """Find ``tag`` items in ``vcalendar``. + + Return a list of items of type ``obj``. + """ items = [] lines = vcalendar.splitlines() diff --git a/radicale/support/__init__.py b/radicale/support/__init__.py index a2ee403..cc4df88 100644 --- a/radicale/support/__init__.py +++ b/radicale/support/__init__.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,6 +18,10 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +""" +Calendar storage support configuration. +""" + from .. import config _support = __import__(config.get("support", "type"), locals(), globals()) diff --git a/radicale/support/plain.py b/radicale/support/plain.py index 989fa21..b8c276c 100644 --- a/radicale/support/plain.py +++ b/radicale/support/plain.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,6 +18,10 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +""" +Plain text storage. +""" + import os import posixpath @@ -25,9 +31,7 @@ from .. import config _folder = os.path.expanduser(config.get("support", "folder")) def calendars(): - """ - List Available Calendars Paths - """ + """List available calendars paths.""" calendars = [] for folder in os.listdir(_folder): @@ -37,40 +41,34 @@ def calendars(): return calendars def mkcalendar(name): - """ - Write new calendar - """ + """Write a new calendar called ``name``.""" user, cal = name.split(posixpath.sep) if not os.path.exists(os.path.join(_folder, user)): os.makedirs(os.path.join(_folder, user)) fd = open(os.path.join(_folder, user, cal), "w") - fd.write(ical.writeCalendar().encode(config.get("encoding", "stock"))) + fd.write(ical.write_calendar().encode(config.get("encoding", "stock"))) def read(cal): - """ - Read cal - """ + """Read calendar ``cal``.""" path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep)) return open(path).read() def append(cal, vcalendar): - """ - Append vcalendar to cal - """ - oldCalendar = unicode(read(cal), config.get("encoding", "stock")) - oldTzs = [tz.tzid for tz in ical.timezones(oldCalendar)] + """Append ``vcalendar`` to ``cal``.""" + old_calendar = unicode(read(cal), config.get("encoding", "stock")) + old_tzs = [tz.tzid for tz in ical.timezones(old_calendar)] path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep)) - oldObjects = [] - oldObjects.extend([event.etag() for event in ical.events(oldCalendar)]) - oldObjects.extend([todo.etag() for todo in ical.todos(oldCalendar)]) + old_objects = [] + old_objects.extend([event.etag() for event in ical.events(old_calendar)]) + old_objects.extend([todo.etag() for todo in ical.todos(old_calendar)]) objects = [] objects.extend(ical.events(vcalendar)) objects.extend(ical.todos(vcalendar)) for tz in ical.timezones(vcalendar): - if tz.tzid not in oldTzs: + if tz.tzid not in old_tzs: # TODO: Manage position, encoding and EOL fd = open(path) lines = [line for line in fd.readlines() if line] @@ -84,7 +82,7 @@ def append(cal, vcalendar): fd.close() for obj in objects: - if obj.etag() not in oldObjects: + if obj.etag() not in old_objects: # TODO: Manage position, encoding and EOL fd = open(path) lines = [line for line in fd.readlines() if line] @@ -98,9 +96,7 @@ def append(cal, vcalendar): fd.close() def remove(cal, etag): - """ - Remove object named uid from cal - """ + """Remove object named ``etag`` from ``cal``.""" path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep)) cal = unicode(read(cal), config.get("encoding", "stock")) @@ -111,11 +107,10 @@ def remove(cal, etag): events = [event for event in ical.events(cal) if event.etag() != etag] fd = open(path, "w") - fd.write(ical.writeCalendar(headers, timezones, todos, events).encode(config.get("encoding", "stock"))) + fd.write(ical.write_calendar(headers, timezones, todos, events).encode(config.get("encoding", "stock"))) fd.close() -if config.get("support", "defaultCalendar"): - user, cal = config.get("support", "defaultCalendar").split(posixpath.sep) +if config.get("support", "calendar"): + user, cal = config.get("support", "calendar").split(posixpath.sep) if not os.path.exists(os.path.join(_folder, user, cal)): - mkcalendar(config.get("support", "defaultCalendar")) - + mkcalendar(config.get("support", "calendar")) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index dc5d5f8..a21055a 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -1,7 +1,9 @@ # -*- coding: utf-8; indent-tabs-mode: nil; -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2008 The Radicale Team +# Copyright © 2008-2009 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,7 +19,7 @@ # along with Radicale. If not, see . """ -XML and iCal requests manager +XML and iCal requests manager. Note that all these functions need to receive unicode objects for full iCal requests (PUT) and string objects with charset correctly defined @@ -32,22 +34,21 @@ import xml.etree.ElementTree as ET import config import ical -# TODO: This is a well-known and accepted hack for ET +# TODO: This is a well-known and accepted hack for ET to avoid ET from renaming +# namespaces, which is accepted in XML norm but often not in XML +# readers. Is there another clean solution to force namespaces? for key,value in config.items("namespace"): ET._namespace_map[value] = key -def _tag(shortName, local): - """ - Get XML Clark notation {uri(shortName)}local - """ - return "{%s}%s"%(config.get("namespace", shortName), local) +def _tag(short_name, local): + """Get XML Clark notation {uri(``short_name``)}``local``.""" + return "{%s}%s"%(config.get("namespace", short_name), local) def delete(obj, calendar, url): - """ - Read and answer DELETE requests - """ - # Read rfc4918-9.6 for info + """Read and answer DELETE requests. + Read rfc4918-9.6 for info. + """ # Reading request calendar.remove(obj) @@ -66,14 +67,13 @@ def delete(obj, calendar, url): return ET.tostring(multistatus, config.get("encoding", "request")) -def propfind(xmlRequest, calendar, url): - """ - Read and answer PROPFIND requests - """ - # Read rfc4918-9.1 for info +def propfind(xml_request, calendar, url): + """Read and answer PROPFIND requests. + Read rfc4918-9.1 for info. + """ # Reading request - root = ET.fromstring(xmlRequest) + root = ET.fromstring(xml_request) propElement = root.find(_tag("D", "prop")) propList = propElement.getchildren() @@ -117,9 +117,7 @@ def propfind(xmlRequest, calendar, url): return ET.tostring(multistatus, config.get("encoding", "request")) def put(icalRequest, calendar, url, obj): - """ - Read PUT requests - """ + """Read PUT requests.""" if obj: # PUT is modifying obj calendar.replace(obj, icalRequest) @@ -127,14 +125,13 @@ def put(icalRequest, calendar, url, obj): # PUT is adding a new object calendar.append(icalRequest) -def report(xmlRequest, calendar, url): - """ - Read and answer REPORT requests - """ - # Read rfc3253-3.6 for info +def report(xml_request, calendar, url): + """Read and answer REPORT requests. + Read rfc3253-3.6 for info. + """ # Reading request - root = ET.fromstring(xmlRequest) + root = ET.fromstring(xml_request) propElement = root.find(_tag("D", "prop")) propList = propElement.getchildren() @@ -209,7 +206,7 @@ def report(xmlRequest, calendar, url): if _tag("C", "calendar-data") in properties: cdata = ET.Element(_tag("C", "calendar-data")) # TODO: Maybe assume that events and todos are not the same - cdata.text = ical.writeCalendar(headers, timezones, [obj]) + cdata.text = ical.write_calendar(headers, timezones, [obj]) prop.append(cdata) status = ET.Element(_tag("D", "status"))