Переглянути джерело

Huge code and copyright cleanup.

git-svn-id: http://svn.32rwr.info/radicale/trunk@9 74e4794c-479d-4a33-9dda-c6c359d70f12
(no author) 16 роки тому
батько
коміт
81f7201399

+ 16 - 12
radicale.py

@@ -2,7 +2,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -23,6 +25,12 @@
 # TODO: Magage command-line options
 # TODO: Magage command-line options
 # TODO: Forget twisted?
 # TODO: Forget twisted?
 
 
+"""
+Radicale Server entry point.
+
+Launch the Radicale Serve according to the configuration.
+"""
+
 import sys
 import sys
 from twisted.web import server
 from twisted.web import server
 from twisted.internet import reactor
 from twisted.internet import reactor
@@ -31,18 +39,14 @@ from twisted.python import log
 import radicale
 import radicale
 
 
 class ServerContextFactory(object):
 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
         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(sys.stdout)
 #log.startLogging(open(radicale.config.get("server", "log"), "w"))
 #log.startLogging(open(radicale.config.get("server", "log"), "w"))

+ 29 - 52
radicale/__init__.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -17,16 +19,15 @@
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
 # TODO: Manage errors (see xmlutils)
 # TODO: Manage errors (see xmlutils)
+# TODO: Forget twisted?
 
 
 from twisted.web.resource import Resource
 from twisted.web.resource import Resource
 from twisted.web import http
 from twisted.web import http
 import posixpath
 import posixpath
 
 
 import config
 import config
-
 import support
 import support
 import acl
 import acl
-
 import xmlutils
 import xmlutils
 import calendar
 import calendar
 
 
@@ -34,112 +35,88 @@ _users = acl.users()
 _calendars = support.calendars()
 _calendars = support.calendars()
 
 
 class CalendarResource(Resource):
 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
     isLeaf = True
 
 
     def __init__(self, user, cal):
     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)
         Resource.__init__(self)
         self.calendar = calendar.Calendar(user, cal)
         self.calendar = calendar.Calendar(user, cal)
 
 
     def render_DELETE(self, request):
     def render_DELETE(self, request):
-        """
-        Manage DELETE requests
-        """
+        """Manage DELETE ``request``."""
         obj = request.getHeader("if-match")
         obj = request.getHeader("if-match")
         answer = xmlutils.delete(obj, self.calendar, str(request.URLPath()))
         answer = xmlutils.delete(obj, self.calendar, str(request.URLPath()))
         request.setResponseCode(http.NO_CONTENT)
         request.setResponseCode(http.NO_CONTENT)
         return answer
         return answer
 
 
     def render_OPTIONS(self, request):
     def render_OPTIONS(self, request):
-        """
-        Manage OPTIONS requests
-        """
+        """Manage OPTIONS ``request``."""
         request.setHeader("Allow", "DELETE, OPTIONS, PROPFIND, PUT, REPORT")
         request.setHeader("Allow", "DELETE, OPTIONS, PROPFIND, PUT, REPORT")
         request.setHeader("DAV", "1, calendar-access")
         request.setHeader("DAV", "1, calendar-access")
         request.setResponseCode(http.OK)
         request.setResponseCode(http.OK)
         return ""
         return ""
 
 
     def render_PROPFIND(self, request):
     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)
         request.setResponseCode(http.MULTI_STATUS)
         return answer
         return answer
 
 
     def render_PUT(self, request):
     def render_PUT(self, request):
-        """
-        Manage PUT requests
-        """
+        """Manage PUT ``request``."""
         # TODO: Improve charset detection
         # TODO: Improve charset detection
         contentType = request.getHeader("content-type")
         contentType = request.getHeader("content-type")
         if contentType and "charset=" in contentType:
         if contentType and "charset=" in contentType:
             charset = contentType.split("charset=")[1].strip()
             charset = contentType.split("charset=")[1].strip()
         else:
         else:
             charset = config.get("encoding", "request")
             charset = config.get("encoding", "request")
-        icalRequest = unicode(request.content.read(), charset)
+        ical_request = request.content.read().decode(charset)
         obj = request.getHeader("if-match")
         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)
         request.setResponseCode(http.CREATED)
         return ""
         return ""
 
 
     def render_REPORT(self, request):
     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)
         request.setResponseCode(http.MULTI_STATUS)
         return answer
         return answer
 
 
 class UserResource(Resource):
 class UserResource(Resource):
-    """
-    Twisted resource for requests at user depth (/user)
-    """
+    """Twisted resource for requests at user depth (/user)."""
     def __init__(self, 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)
         Resource.__init__(self)
         for cal in _calendars:
         for cal in _calendars:
             if cal.startswith("%s%s"%(user, posixpath.sep)):
             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):
     def getChild(self, cal, request):
-        """
-        Get calendar resource if user exists
-        """
+        """Get calendar resource if ``cal`` exists."""
         if cal in _calendars:
         if cal in _calendars:
             return Resource.getChild(self, cal, request)
             return Resource.getChild(self, cal, request)
         else:
         else:
             return self
             return self
 
 
 class HttpResource(Resource):
 class HttpResource(Resource):
-    """
-    Twisted resource for requests at root depth (/)
-    """
+    """Twisted resource for requests at root depth (/)."""
     def __init__(self):
     def __init__(self):
-        """
-        Initialize resource by connecting children requests to
-        the users resources
-        """
+        """Initialize by connecting requests to the users resources."""
         Resource.__init__(self)
         Resource.__init__(self)
         for user in _users:
         for user in _users:
             self.putChild(user, UserResource(user))
             self.putChild(user, UserResource(user))
 
 
     def getChild(self, user, request):
     def getChild(self, user, request):
-        """
-        Get user resource if user exists
-        """
+        """Get user resource if ``user`` exists."""
         if user in _users:
         if user in _users:
             return Resource.getChild(self, user, request)
             return Resource.getChild(self, user, request)
         else:
         else:

+ 10 - 1
radicale/acl/__init__.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # 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
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
+"""
+Users and rights management.
+
+This module loads a list of users with access rights, according to the acl
+configuration.
+"""
+
 from .. import config
 from .. import config
 
 
 _acl = __import__(config.get("acl", "type"), locals(), globals())
 _acl = __import__(config.get("acl", "type"), locals(), globals())

+ 11 - 5
radicale/acl/fake.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # 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
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
+"""
+Fake ACL.
+
+Just load the default user set in configuration, with no rights management.
+"""
+
 from .. import config
 from .. import config
 
 
 def users():
 def users():
-    """
-    Get the List of all Users
-    """
-    return [config.get("acl", "defaultUser")]
+    """Get the list of all users."""
+    return [config.get("acl", "user")]

+ 14 - 5
radicale/acl/htpasswd.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # 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
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
+"""
+Htpasswd ACL.
+
+Load the list of users according to the htpasswd configuration.
+"""
+
+# TODO: Manage rights
+
 from .. import config
 from .. import config
 
 
 def users():
 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()]

+ 32 - 36
radicale/calendar.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # 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
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
-# 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
 import support
 
 
+hash_tag = lambda vcalendar: str(hash(vcalendar))
+
 class Calendar(object):
 class Calendar(object):
-    """
-    Internal Calendar Class
-    """
+    """Internal calendar class."""
     def __init__(self, user, cal):
     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.encoding = "utf-8"
         self.owner = "lize"
         self.owner = "lize"
         self.user = user
         self.user = user
         self.cal = cal
         self.cal = cal
         self.version = "2.0"
         self.version = "2.0"
-        self.ctag = str(hash(self.vcalendar()))
+        self.ctag = hash_tag(self.vcalendar())
 
 
     def append(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)
         support.append(self.cal, vcalendar)
 
 
     def remove(self, uid):
     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)
         support.remove(self.cal, uid)
 
 
     def replace(self, uid, vcalendar):
     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.remove(self.cal, uid)
         support.append(self.cal, vcalendar)
         support.append(self.cal, vcalendar)
 
 
     def vcalendar(self):
     def vcalendar(self):
+        """Return unicode calendar from the calendar."""
         return unicode(support.read(self.cal), self.encoding)
         return unicode(support.read(self.cal), self.encoding)
 
 
 class Event(object):
 class Event(object):
-    """
-    Internal Event Class
-    """
-    # TODO: Fix the behaviour if no UID is given
+    """Internal event class."""
     def __init__(self, vcalendar):
     def __init__(self, vcalendar):
+        """Initialize event from ``vcalendar``."""
         self.text = vcalendar
         self.text = vcalendar
 
 
     def etag(self):
     def etag(self):
-        return str(hash(self.text))
+        """Return etag from event."""
+        return hash_tag(self.text)
 
 
 class Header(object):
 class Header(object):
-    """
-    Internal Headers Class
-    """
+    """Internal header class."""
     def __init__(self, vcalendar):
     def __init__(self, vcalendar):
+        """Initialize header from ``vcalendar``."""
         self.text = vcalendar
         self.text = vcalendar
 
 
 class Timezone(object):
 class Timezone(object):
-    """
-    Internal Timezone Class
-    """
+    """Internal timezone class."""
     def __init__(self, vcalendar):
     def __init__(self, vcalendar):
+        """Initialize timezone from ``vcalendar``."""
         lines = vcalendar.splitlines()
         lines = vcalendar.splitlines()
         for line in lines:
         for line in lines:
             if line.startswith("TZID:"):
             if line.startswith("TZID:"):
@@ -92,12 +89,11 @@ class Timezone(object):
         self.text = vcalendar
         self.text = vcalendar
 
 
 class Todo(object):
 class Todo(object):
-    """
-    Internal Todo Class
-    """
-    # TODO: Fix the behaviour if no UID is given
+    """Internal todo class."""
     def __init__(self, vcalendar):
     def __init__(self, vcalendar):
+        """Initialize todo from ``vcalendar``."""
         self.text = vcalendar
         self.text = vcalendar
 
 
     def etag(self):
     def etag(self):
-        return str(hash(self.text))
+        """Return etag from todo."""
+        return hash_tag(self.text)

+ 12 - 7
radicale/config.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # 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
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
+"""
+Radicale configuration module.
+
+Give a configparser-like interface to read and write configuration.
+"""
+
 from ConfigParser import RawConfigParser as ConfigParser
 from ConfigParser import RawConfigParser as ConfigParser
 
 
-# Default functions
 _config = ConfigParser()
 _config = ConfigParser()
 get = _config.get
 get = _config.get
 set = _config.set
 set = _config.set
@@ -28,7 +35,6 @@ getfloat = _config.getfloat
 options = _config.options
 options = _config.options
 items = _config.items
 items = _config.items
 
 
-# Default config
 _initial = {
 _initial = {
     "server": {
     "server": {
         "type": "http",
         "type": "http",
@@ -53,20 +59,19 @@ _initial = {
     "acl": {
     "acl": {
         "type": "fake",
         "type": "fake",
         "filename": "/etc/radicale/users",
         "filename": "/etc/radicale/users",
-        "defaultUser": "radicale",
+        "user": "radicale",
         },
         },
     "support": {
     "support": {
         "type": "plain",
         "type": "plain",
         "folder": "~/.config/radicale",
         "folder": "~/.config/radicale",
-        "defaultCalendar": "radicale/calendar",
+        "calendar": "radicale/calendar",
         },
         },
     }
     }
 
 
-# Set the default config
 for section, values in _initial.iteritems():
 for section, values in _initial.iteritems():
     _config.add_section(section)
     _config.add_section(section)
     for key, value in values.iteritems():
     for key, value in values.iteritems():
         _config.set(section, key, value)
         _config.set(section, key, value)
 
 
-# Set the user config
+# TODO: Use abstract filename for other platforms
 _config.read("/etc/radicale/config")
 _config.read("/etc/radicale/config")

+ 16 - 9
radicale/ical.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # 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
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
+"""
+iCal parsing functions.
+"""
+
 # TODO: Manage filters (see xmlutils)
 # TODO: Manage filters (see xmlutils)
 
 
 import calendar
 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=[]):
                   timezones=[], todos=[], events=[]):
-    """
-    Create calendar from headers, timezones, todos, events
-    """
+    """Create calendar from ``headers``, ``timezones``, ``todos``, ``events``."""
     # TODO: Manage encoding and EOL
     # TODO: Manage encoding and EOL
     cal = u"\n".join((
     cal = u"\n".join((
         u"BEGIN:VCALENDAR",
         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])
     return u"\n".join([line for line in cal.splitlines() if line])
 
 
 def headers(vcalendar):
 def headers(vcalendar):
-    """
-    Find Headers Items in vcalendar
-    """
+    """Find Headers items in ``vcalendar``."""
     headers = []
     headers = []
 
 
     lines = vcalendar.splitlines()
     lines = vcalendar.splitlines()
@@ -53,6 +56,10 @@ def headers(vcalendar):
     return headers
     return headers
 
 
 def _parse(vcalendar, tag, obj):
 def _parse(vcalendar, tag, obj):
+    """Find ``tag`` items in ``vcalendar``.
+    
+    Return a list of items of type ``obj``.
+    """
     items = []
     items = []
 
 
     lines = vcalendar.splitlines()
     lines = vcalendar.splitlines()

+ 7 - 1
radicale/support/__init__.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # 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
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
+"""
+Calendar storage support configuration.
+"""
+
 from .. import config
 from .. import config
 
 
 _support = __import__(config.get("support", "type"), locals(), globals())
 _support = __import__(config.get("support", "type"), locals(), globals())

+ 24 - 29
radicale/support/plain.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # 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
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
+"""
+Plain text storage.
+"""
+
 import os
 import os
 import posixpath
 import posixpath
 
 
@@ -25,9 +31,7 @@ from .. import config
 _folder = os.path.expanduser(config.get("support", "folder"))
 _folder = os.path.expanduser(config.get("support", "folder"))
 
 
 def calendars():
 def calendars():
-    """
-    List Available Calendars Paths
-    """
+    """List available calendars paths."""
     calendars = []
     calendars = []
 
 
     for folder in os.listdir(_folder):
     for folder in os.listdir(_folder):
@@ -37,40 +41,34 @@ def calendars():
     return calendars
     return calendars
 
 
 def mkcalendar(name):
 def mkcalendar(name):
-    """
-    Write new calendar
-    """
+    """Write a new calendar called ``name``."""
     user, cal = name.split(posixpath.sep)
     user, cal = name.split(posixpath.sep)
     if not os.path.exists(os.path.join(_folder, user)):
     if not os.path.exists(os.path.join(_folder, user)):
         os.makedirs(os.path.join(_folder, user))
         os.makedirs(os.path.join(_folder, user))
     fd = open(os.path.join(_folder, user, cal), "w")
     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):
 def read(cal):
-    """
-    Read cal
-    """
+    """Read calendar ``cal``."""
     path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
     path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
     return open(path).read()
     return open(path).read()
 
 
 def append(cal, vcalendar):
 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))
     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 = []
     objects.extend(ical.events(vcalendar))
     objects.extend(ical.events(vcalendar))
     objects.extend(ical.todos(vcalendar))
     objects.extend(ical.todos(vcalendar))
 
 
     for tz in ical.timezones(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
             # TODO: Manage position, encoding and EOL
             fd = open(path)
             fd = open(path)
             lines = [line for line in fd.readlines() if line]
             lines = [line for line in fd.readlines() if line]
@@ -84,7 +82,7 @@ def append(cal, vcalendar):
             fd.close()
             fd.close()
 
 
     for obj in objects:
     for obj in objects:
-        if obj.etag() not in oldObjects:
+        if obj.etag() not in old_objects:
             # TODO: Manage position, encoding and EOL
             # TODO: Manage position, encoding and EOL
             fd = open(path)
             fd = open(path)
             lines = [line for line in fd.readlines() if line]
             lines = [line for line in fd.readlines() if line]
@@ -98,9 +96,7 @@ def append(cal, vcalendar):
             fd.close()
             fd.close()
 
 
 def remove(cal, etag):
 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))
     path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
 
 
     cal = unicode(read(cal), config.get("encoding", "stock"))
     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]
     events = [event for event in ical.events(cal) if event.etag() != etag]
 
 
     fd = open(path, "w")
     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()
     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)):
     if not os.path.exists(os.path.join(_folder, user, cal)):
-        mkcalendar(config.get("support", "defaultCalendar"))
-
+        mkcalendar(config.get("support", "calendar"))

+ 25 - 28
radicale/xmlutils.py

@@ -1,7 +1,9 @@
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 # -*- coding: utf-8; indent-tabs-mode: nil; -*-
 #
 #
 # This file is part of Radicale Server - Calendar Server
 # 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
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -17,7 +19,7 @@
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
 
 """
 """
-XML and iCal requests manager
+XML and iCal requests manager.
 
 
 Note that all these functions need to receive unicode objects for full
 Note that all these functions need to receive unicode objects for full
 iCal requests (PUT) and string objects with charset correctly defined
 iCal requests (PUT) and string objects with charset correctly defined
@@ -32,22 +34,21 @@ import xml.etree.ElementTree as ET
 import config
 import config
 import ical
 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"):
 for key,value in config.items("namespace"):
     ET._namespace_map[value] = key
     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):
 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
     # Reading request
     calendar.remove(obj)
     calendar.remove(obj)
 
 
@@ -66,14 +67,13 @@ def delete(obj, calendar, url):
 
 
     return ET.tostring(multistatus, config.get("encoding", "request"))
     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
     # Reading request
-    root = ET.fromstring(xmlRequest)
+    root = ET.fromstring(xml_request)
 
 
     propElement = root.find(_tag("D", "prop"))
     propElement = root.find(_tag("D", "prop"))
     propList = propElement.getchildren()
     propList = propElement.getchildren()
@@ -117,9 +117,7 @@ def propfind(xmlRequest, calendar, url):
     return ET.tostring(multistatus, config.get("encoding", "request"))
     return ET.tostring(multistatus, config.get("encoding", "request"))
 
 
 def put(icalRequest, calendar, url, obj):
 def put(icalRequest, calendar, url, obj):
-    """
-    Read PUT requests
-    """
+    """Read PUT requests."""
     if obj:
     if obj:
         # PUT is modifying obj
         # PUT is modifying obj
         calendar.replace(obj, icalRequest)
         calendar.replace(obj, icalRequest)
@@ -127,14 +125,13 @@ def put(icalRequest, calendar, url, obj):
         # PUT is adding a new object
         # PUT is adding a new object
         calendar.append(icalRequest)
         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
     # Reading request
-    root = ET.fromstring(xmlRequest)
+    root = ET.fromstring(xml_request)
 
 
     propElement = root.find(_tag("D", "prop"))
     propElement = root.find(_tag("D", "prop"))
     propList = propElement.getchildren()
     propList = propElement.getchildren()
@@ -209,7 +206,7 @@ def report(xmlRequest, calendar, url):
             if _tag("C", "calendar-data") in properties:
             if _tag("C", "calendar-data") in properties:
                 cdata = ET.Element(_tag("C", "calendar-data"))
                 cdata = ET.Element(_tag("C", "calendar-data"))
                 # TODO: Maybe assume that events and todos are not the same
                 # 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)
                 prop.append(cdata)
 
 
             status = ET.Element(_tag("D", "status"))
             status = ET.Element(_tag("D", "status"))