From 06843adca159ec389438a52e79b24f03d230d9df Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Tue, 19 Jan 2010 20:31:21 +0100 Subject: [PATCH] Add docstrings and use @property when needed. --- radicale.py | 2 +- radicale/__init__.py | 52 ++++++++++++++++++++++++++------------- radicale/calendar.py | 22 ++++++++++------- radicale/support/plain.py | 10 ++++---- radicale/xmlutils.py | 12 ++++----- 5 files changed, 60 insertions(+), 38 deletions(-) diff --git a/radicale.py b/radicale.py index ccc5e6e..6708064 100755 --- a/radicale.py +++ b/radicale.py @@ -64,7 +64,7 @@ parser.add_option( help="certificate file ") options, args = parser.parse_args() -# Update radicale configuration according to options +# Update Radicale configuration according to options for option in parser.option_list: key = option.dest if key: diff --git a/radicale/__init__.py b/radicale/__init__.py index 5564b18..7d0a8cf 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -18,6 +18,21 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +""" +Radicale Server module. + +This module offers 3 useful classes: + +- ``HTTPServer`` is a simple HTTP server; +- ``HTTPSServer`` is a HTTPS server, wrapping the HTTP server in a socket + managing SSL connections; +- ``CalendarHTTPHandler`` is a CalDAV request handler for HTTP(S) servers. + +To use this module, you should take a look at the file ``radicale.py`` that +should have been included in this package. + +""" + # TODO: Manage errors (see xmlutils) import socket @@ -29,10 +44,14 @@ except ImportError: from radicale import config, support, xmlutils -HTTPServer = server.HTTPServer +class HTTPServer(server.HTTPServer): + """HTTP server.""" + pass class HTTPSServer(HTTPServer): + """HTTPS server.""" def __init__(self, address, handler): + """Create server by wrapping HTTP socket in an SSL socket.""" # Fails with Python 2.5, import if needed import ssl @@ -44,20 +63,23 @@ class HTTPSServer(HTTPServer): keyfile=config.get("server", "key"), ssl_version=ssl.PROTOCOL_SSLv23) self.server_bind() - self.server_activate() + self.server_activate() class CalendarHTTPHandler(server.BaseHTTPRequestHandler): """HTTP requests handler for calendars.""" - def _parse_path(self): + _encoding = config.get("encoding", "request") + + @property + def calendar(self): + """The ``calendar.Calendar`` object corresponding to the given path.""" path = self.path.strip("/").split("/") if len(path) >= 2: cal = "%s/%s" % (path[0], path[1]) - self.calendar = calendar.Calendar("radicale", cal) + return calendar.Calendar("radicale", cal) def do_GET(self): - """Manage GET ``request``.""" - self._parse_path() - answer = self.calendar.vcalendar().encode(config.get("encoding", "request")) + """Manage GET request.""" + answer = self.calendar.vcalendar.encode(_encoding) self.send_response(client.OK) self.send_header("Content-Length", len(answer)) @@ -65,8 +87,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): self.wfile.write(answer) def do_DELETE(self): - """Manage DELETE ``request``.""" - self._parse_path() + """Manage DELETE request.""" obj = self.headers.get("if-match", None) answer = xmlutils.delete(obj, self.calendar, self.path) @@ -76,15 +97,14 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): self.wfile.write(answer) def do_OPTIONS(self): - """Manage OPTIONS ``request``.""" + """Manage OPTIONS request.""" self.send_response(client.OK) self.send_header("Allow", "DELETE, GET, OPTIONS, PROPFIND, PUT, REPORT") self.send_header("DAV", "1, calendar-access") self.end_headers() def do_PROPFIND(self): - """Manage PROPFIND ``request``.""" - self._parse_path() + """Manage PROPFIND request.""" xml_request = self.rfile.read(int(self.headers["Content-Length"])) answer = xmlutils.propfind(xml_request, self.calendar, self.path) @@ -95,14 +115,13 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): self.wfile.write(answer) def do_PUT(self): - """Manage PUT ``request``.""" + """Manage PUT request.""" # TODO: Improve charset detection - self._parse_path() contentType = self.headers["content-type"] if contentType and "charset=" in contentType: charset = contentType.split("charset=")[1].strip() else: - charset = config.get("encoding", "request") + charset = self._encoding ical_request = self.rfile.read(int(self.headers["Content-Length"])).decode(charset) obj = self.headers.get("if-match", None) xmlutils.put(ical_request, self.calendar, self.path, obj) @@ -110,8 +129,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler): self.send_response(client.CREATED) def do_REPORT(self): - """Manage REPORT ``request``.""" - self._parse_path() + """Manage REPORT request.""" xml_request = self.rfile.read(int(self.headers["Content-Length"])) answer = xmlutils.report(xml_request, self.calendar, self.path) diff --git a/radicale/calendar.py b/radicale/calendar.py index 06abba2..aeb5ab0 100644 --- a/radicale/calendar.py +++ b/radicale/calendar.py @@ -39,31 +39,33 @@ class Calendar(object): self.user = user self.cal = cal self.version = "2.0" - self.ctag = hash_tag(self.vcalendar()) + self.ctag = hash_tag(self.vcalendar) def append(self, vcalendar): """Append vcalendar to the calendar.""" - self.ctag = hash_tag(self.vcalendar()) + self.ctag = hash_tag(self.vcalendar) self.support.append(self.cal, vcalendar) def remove(self, uid): """Remove object named ``uid`` from the calendar.""" - self.ctag = hash_tag(self.vcalendar()) + self.ctag = hash_tag(self.vcalendar) self.support.remove(self.cal, uid) def replace(self, uid, vcalendar): """Replace objet named ``uid`` by ``vcalendar`` in the calendar.""" - self.ctag = hash_tag(self.vcalendar()) + self.ctag = hash_tag(self.vcalendar) self.support.remove(self.cal, uid) self.support.append(self.cal, vcalendar) + @property def vcalendar(self): - """Return unicode calendar from the calendar.""" + """Unicode calendar from the calendar.""" return self.support.read(self.cal) + @property def etag(self): - """Return etag from calendar.""" - return '"%s"' % hash_tag(self.vcalendar()) + """Etag from calendar.""" + return '"%s"' % hash_tag(self.vcalendar) class Event(object): """Internal event class.""" @@ -71,8 +73,9 @@ class Event(object): """Initialize event from ``vcalendar``.""" self.text = vcalendar + @property def etag(self): - """Return etag from event.""" + """Etag from event.""" return '"%s"' % hash_tag(self.text) class Header(object): @@ -99,6 +102,7 @@ class Todo(object): """Initialize todo from ``vcalendar``.""" self.text = vcalendar + @property def etag(self): - """Return etag from todo.""" + """Etag from todo.""" return hash_tag(self.text) diff --git a/radicale/support/plain.py b/radicale/support/plain.py index f22db49..299a5a7 100644 --- a/radicale/support/plain.py +++ b/radicale/support/plain.py @@ -63,8 +63,8 @@ def append(cal, vcalendar): path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep)) 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)]) + 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)) @@ -85,7 +85,7 @@ def append(cal, vcalendar): fd.close() for obj in objects: - if obj.etag() not in old_objects: + if obj.etag not in old_objects: # TODO: Manage position and EOL fd = _open(path) lines = [line for line in fd.readlines() if line] @@ -106,8 +106,8 @@ def remove(cal, etag): headers = ical.headers(cal) timezones = ical.timezones(cal) - todos = [todo for todo in ical.todos(cal) if todo.etag() != etag] - events = [event for event in ical.events(cal) if event.etag() != etag] + todos = [todo for todo in ical.todos(cal) if todo.etag != etag] + events = [event for event in ical.events(cal) if event.etag != etag] fd = _open(path, "w") fd.write(ical.write_calendar(headers, timezones, todos, events)) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 51e614e..f19b56b 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -114,7 +114,7 @@ def propfind(xml_request, calendar, url): if _tag("D", "getetag") in properties: getetag = ET.Element(_tag("D", "getetag")) - getetag.text = calendar.etag() + getetag.text = calendar.etag prop.append(getetag) if _tag("CS", "getctag") in properties: @@ -172,13 +172,13 @@ def report(xml_request, calendar, url): # is that really what is needed? # Read rfc4791-9.[6|10] for info for hreference in hreferences: - headers = ical.headers(calendar.vcalendar()) + headers = ical.headers(calendar.vcalendar) # TODO: Define timezones by obj - timezones = ical.timezones(calendar.vcalendar()) + timezones = ical.timezones(calendar.vcalendar) objects = [] - objects.extend(ical.events(calendar.vcalendar())) - objects.extend(ical.todos(calendar.vcalendar())) + objects.extend(ical.events(calendar.vcalendar)) + objects.extend(ical.todos(calendar.vcalendar)) if not objects: # TODO: Read rfc4791-9.[6|10] to find a right answer @@ -212,7 +212,7 @@ def report(xml_request, calendar, url): if _tag("D", "getetag") in properties: # TODO: Can UID and ETAG be the same? getetag = ET.Element(_tag("D", "getetag")) - getetag.text = obj.etag() + getetag.text = obj.etag prop.append(getetag) if _tag("C", "calendar-data") in properties: