Python 3 support and minor fixes.

This commit is contained in:
Guillaume Ayoub 2010-01-15 16:04:03 +01:00
parent 4a0d3936e8
commit 4ee09cf817
11 changed files with 66 additions and 70 deletions

View File

@ -30,13 +30,10 @@ Radicale Server entry point.
Launch the Radicale Serve according to the configuration. Launch the Radicale Serve according to the configuration.
""" """
import sys
import BaseHTTPServer
import radicale import radicale
if radicale.config.get("server", "type") == "http": if radicale.config.get("server", "type") == "http":
server = BaseHTTPServer.HTTPServer( server = radicale.server.HTTPServer(
("", radicale.config.getint("server", "port")), ("", radicale.config.getint("server", "port")),
radicale.CalendarHandler) radicale.CalendarHandler)
server.serve_forever() server.serve_forever()

View File

@ -21,25 +21,21 @@
# TODO: Manage errors (see xmlutils) # TODO: Manage errors (see xmlutils)
import posixpath import posixpath
import httplib try:
import BaseHTTPServer from http import client, server
except ImportError:
import httplib as client
import BaseHTTPServer as server
import config from radicale import config, support, xmlutils
import support
import acl
import xmlutils
import calendar
_users = acl.users() class CalendarHandler(server.BaseHTTPRequestHandler):
_calendars = support.calendars()
class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""HTTP requests handler for calendars.""" """HTTP requests handler for calendars."""
def _parse_path(self): def _parse_path(self):
path = self.path.strip("/").split("/") path = self.path.strip("/").split("/")
if len(path) >= 2: if len(path) >= 2:
cal = "%s/%s" % (path[0], path[1]) cal = "%s/%s" % (path[0], path[1])
self.calendar = calendar.Calendar(_users[0], cal) self.calendar = calendar.Calendar("radicale", cal)
def do_DELETE(self): def do_DELETE(self):
"""Manage DELETE ``request``.""" """Manage DELETE ``request``."""
@ -47,14 +43,14 @@ class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
obj = self.headers.get("if-match", None) obj = self.headers.get("if-match", None)
answer = xmlutils.delete(obj, self.calendar, self.path) answer = xmlutils.delete(obj, self.calendar, self.path)
self.send_response(httplib.NO_CONTENT) self.send_response(client.NO_CONTENT)
self.send_header("Content-Length", len(answer)) self.send_header("Content-Length", len(answer))
self.end_headers() self.end_headers()
self.wfile.write(answer) self.wfile.write(answer)
def do_OPTIONS(self): def do_OPTIONS(self):
"""Manage OPTIONS ``request``.""" """Manage OPTIONS ``request``."""
self.send_response(httplib.OK) self.send_response(client.OK)
self.send_header("Allow", "DELETE, OPTIONS, PROPFIND, PUT, REPORT") self.send_header("Allow", "DELETE, OPTIONS, PROPFIND, PUT, REPORT")
self.send_header("DAV", "1, calendar-access") self.send_header("DAV", "1, calendar-access")
self.end_headers() self.end_headers()
@ -65,7 +61,7 @@ class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
xml_request = self.rfile.read(int(self.headers["Content-Length"])) xml_request = self.rfile.read(int(self.headers["Content-Length"]))
answer = xmlutils.propfind(xml_request, self.calendar, self.path) answer = xmlutils.propfind(xml_request, self.calendar, self.path)
self.send_response(httplib.MULTI_STATUS) self.send_response(client.MULTI_STATUS)
self.send_header("DAV", "1, calendar-access") self.send_header("DAV", "1, calendar-access")
self.send_header("Content-Length", len(answer)) self.send_header("Content-Length", len(answer))
self.end_headers() self.end_headers()
@ -84,7 +80,7 @@ class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
obj = self.headers.get("if-match", None) obj = self.headers.get("if-match", None)
xmlutils.put(ical_request, self.calendar, self.path, obj) xmlutils.put(ical_request, self.calendar, self.path, obj)
self.send_response(httplib.CREATED) self.send_response(client.CREATED)
def do_REPORT(self): def do_REPORT(self):
"""Manage REPORT ``request``.""" """Manage REPORT ``request``."""
@ -92,7 +88,7 @@ class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
xml_request = self.rfile.read(int(self.headers["Content-Length"])) xml_request = self.rfile.read(int(self.headers["Content-Length"]))
answer = xmlutils.report(xml_request, self.calendar, self.path) answer = xmlutils.report(xml_request, self.calendar, self.path)
self.send_response(httplib.MULTI_STATUS) self.send_response(client.MULTI_STATUS)
self.send_header("Content-Length", len(answer)) self.send_header("Content-Length", len(answer))
self.end_headers() self.end_headers()
self.wfile.write(answer) self.wfile.write(answer)

View File

@ -25,7 +25,7 @@ This module loads a list of users with access rights, according to the acl
configuration. configuration.
""" """
from .. import config from radicale import config
_acl = __import__(config.get("acl", "type"), locals(), globals()) _acl = __import__(config.get("acl", "type"), locals(), globals())

View File

@ -24,7 +24,7 @@ Fake ACL.
Just load the default user set in configuration, with no rights management. Just load the default user set in configuration, with no rights management.
""" """
from .. import config from radicale import config
def users(): def users():
"""Get the list of all users.""" """Get the list of all users."""

View File

@ -26,7 +26,7 @@ Load the list of users according to the htpasswd configuration.
# TODO: Manage rights # TODO: Manage rights
from .. import config from radicale import config
def users(): def users():
"""Get the list of all users.""" """Get the list of all users."""

View File

@ -24,7 +24,7 @@ Radicale calendar classes.
Define the main classes of a calendar as seen from the server. Define the main classes of a calendar as seen from the server.
""" """
import support from radicale import support
hash_tag = lambda vcalendar: str(hash(vcalendar)) hash_tag = lambda vcalendar: str(hash(vcalendar))
@ -33,8 +33,9 @@ class Calendar(object):
def __init__(self, user, cal): def __init__(self, user, cal):
"""Initialize the calendar with ``cal`` and ``user`` parameters.""" """Initialize the calendar with ``cal`` and ``user`` parameters."""
# TODO: Use properties from the calendar configuration # TODO: Use properties from the calendar configuration
self.support = support.load()
self.encoding = "utf-8" self.encoding = "utf-8"
self.owner = "lize" self.owner = "radicale"
self.user = user self.user = user
self.cal = cal self.cal = cal
self.version = "2.0" self.version = "2.0"
@ -43,22 +44,22 @@ class Calendar(object):
def append(self, vcalendar): def append(self, vcalendar):
"""Append vcalendar to the calendar.""" """Append vcalendar to the calendar."""
self.ctag = hash_tag(self.vcalendar()) self.ctag = hash_tag(self.vcalendar())
support.append(self.cal, vcalendar) self.support.append(self.cal, vcalendar)
def remove(self, uid): def remove(self, uid):
"""Remove object named ``uid`` from the calendar.""" """Remove object named ``uid`` from the calendar."""
self.ctag = hash_tag(self.vcalendar()) self.ctag = hash_tag(self.vcalendar())
support.remove(self.cal, uid) self.support.remove(self.cal, uid)
def replace(self, uid, vcalendar): def replace(self, uid, vcalendar):
"""Replace objet named ``uid`` by ``vcalendar`` in the calendar.""" """Replace objet named ``uid`` by ``vcalendar`` in the calendar."""
self.ctag = hash_tag(self.vcalendar()) self.ctag = hash_tag(self.vcalendar())
support.remove(self.cal, uid) self.support.remove(self.cal, uid)
support.append(self.cal, vcalendar) self.support.append(self.cal, vcalendar)
def vcalendar(self): def vcalendar(self):
"""Return unicode calendar from the calendar.""" """Return unicode calendar from the calendar."""
return unicode(support.read(self.cal), self.encoding) return self.support.read(self.cal)
def etag(self): def etag(self):
"""Return etag from calendar.""" """Return etag from calendar."""

View File

@ -24,7 +24,10 @@ Radicale configuration module.
Give a configparser-like interface to read and write configuration. Give a configparser-like interface to read and write configuration.
""" """
from ConfigParser import RawConfigParser as ConfigParser try:
from configparser import RawConfigParser as ConfigParser
except ImportError:
from ConfigParser import RawConfigParser as ConfigParser
_config = ConfigParser() _config = ConfigParser()
get = _config.get get = _config.get
@ -68,9 +71,9 @@ _initial = {
}, },
} }
for section, values in _initial.iteritems(): for section, values in _initial.items():
_config.add_section(section) _config.add_section(section)
for key, value in values.iteritems(): for key, value in values.items():
_config.set(section, key, value) _config.set(section, key, value)
# TODO: Use abstract filename for other platforms # TODO: Use abstract filename for other platforms

View File

@ -24,7 +24,7 @@ iCal parsing functions.
# TODO: Manage filters (see xmlutils) # TODO: Manage filters (see xmlutils)
import calendar from radicale import calendar
def write_calendar(headers=[ def write_calendar(headers=[
calendar.Header("PRODID:-//Radicale//NONSGML Radicale Server//EN"), calendar.Header("PRODID:-//Radicale//NONSGML Radicale Server//EN"),
@ -32,14 +32,14 @@ def write_calendar(headers=[
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 = "\n".join((
u"BEGIN:VCALENDAR", "BEGIN:VCALENDAR",
u"\n".join([header.text for header in headers]), "\n".join([header.text for header in headers]),
u"\n".join([timezone.text for timezone in timezones]), "\n".join([timezone.text for timezone in timezones]),
u"\n".join([todo.text for todo in todos]), "\n".join([todo.text for todo in todos]),
u"\n".join([event.text for event in events]), "\n".join([event.text for event in events]),
u"END:VCALENDAR")) "END:VCALENDAR"))
return u"\n".join([line for line in cal.splitlines() if line]) return "\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``."""

View File

@ -22,12 +22,9 @@
Calendar storage support configuration. Calendar storage support configuration.
""" """
from .. import config from radicale import config
_support = __import__(config.get("support", "type"), locals(), globals()) def load():
module = __import__("radicale.support", globals(), locals(),
append = _support.append [config.get("support", "type")])
calendars =_support.calendars return getattr(module, config.get("support", "type"))
mkcalendar =_support.mkcalendar
read = _support.read
remove = _support.remove

View File

@ -24,12 +24,15 @@ Plain text storage.
import os import os
import posixpath import posixpath
import codecs
from .. import ical from radicale import config, ical
from .. import config
_folder = os.path.expanduser(config.get("support", "folder")) _folder = os.path.expanduser(config.get("support", "folder"))
def _open(path, mode="r"):
return codecs.open(path, mode, config.get("encoding", "stock"))
def calendars(): def calendars():
"""List available calendars paths.""" """List available calendars paths."""
calendars = [] calendars = []
@ -45,17 +48,17 @@ def mkcalendar(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.write_calendar().encode(config.get("encoding", "stock"))) fd.write(ical.write_calendar())
def read(cal): def read(cal):
"""Read calendar ``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``.""" """Append ``vcalendar`` to ``cal``."""
old_calendar = unicode(read(cal), config.get("encoding", "stock")) old_calendar = read(cal)
old_tzs = [tz.tzid for tz in ical.timezones(old_calendar)] 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))
@ -69,29 +72,29 @@ def append(cal, vcalendar):
for tz in ical.timezones(vcalendar): for tz in ical.timezones(vcalendar):
if tz.tzid not in old_tzs: if tz.tzid not in old_tzs:
# TODO: Manage position, encoding and EOL # TODO: Manage position 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]
fd.close() fd.close()
for i,line in enumerate(tz.text.splitlines()): for i,line in enumerate(tz.text.splitlines()):
lines.insert(2+i, line.encode(config.get("encoding", "stock"))+"\n") lines.insert(2 + i, line + "\n")
fd = open(path, "w") fd = _open(path, "w")
fd.writelines(lines) fd.writelines(lines)
fd.close() fd.close()
for obj in objects: for obj in objects:
if obj.etag() not in old_objects: if obj.etag() not in old_objects:
# TODO: Manage position, encoding and EOL # TODO: Manage position 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]
fd.close() fd.close()
for line in obj.text.splitlines(): for line in obj.text.splitlines():
lines.insert(-1, line.encode(config.get("encoding", "stock"))+"\n") lines.insert(-1, line + "\n")
fd = open(path, "w") fd = _open(path, "w")
fd.writelines(lines) fd.writelines(lines)
fd.close() fd.close()
@ -99,15 +102,15 @@ def remove(cal, etag):
"""Remove object named ``etag`` 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 = read(cal)
headers = ical.headers(cal) headers = ical.headers(cal)
timezones = ical.timezones(cal) timezones = ical.timezones(cal)
todos = [todo for todo in ical.todos(cal) if todo.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] events = [event for event in ical.events(cal) if event.etag() != etag]
fd = open(path, "w") fd = _open(path, "w")
fd.write(ical.write_calendar(headers, timezones, todos, events).encode(config.get("encoding", "stock"))) fd.write(ical.write_calendar(headers, timezones, todos, events))
fd.close() fd.close()
if config.get("support", "calendar"): if config.get("support", "calendar"):

View File

@ -31,8 +31,7 @@ in them for XML requests (all but PUT).
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import config from radicale import config, ical
import ical
# TODO: This is a well-known and accepted hack for ET to avoid ET from renaming # 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 # namespaces, which is accepted in XML norm but often not in XML