Save the ions!

Introducing (python-)caldav

During the last few days, I’ve been busy writing a CalDAV client library for work. This is a requirement because we are going to integrate calendars from various sources in one of our websites.

CalDAV is clearly the way to go, but as far as libraries go, the only one I’ve been able to find was CalDAVClientLibrary, which, quite frankly, scares me. I’m already familiar with CalendarServer, and I can’t qualify that as “lightweight”, “simple” or “easily installable”.

CalDAV

In case you don’t know what CalDAV is, it’s an extension to webdav for calendaring, and is defined in rfc4791. If you don’t feel like reading all of this, it’s mostly HTTP with XML requests and responses, but not always, which is why it gets kind of weird…

Example requests

Creating a calendar:

MKCOL /calendars/pythoncaldav-test HTTP/1.1
Host: example.com
Accept-Encoding: identity
Content-Length: 249

<?xml version='1.0' encoding='utf-8'?>
<D:mkcol xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:D="DAV:">
  <D:set>
    <D:prop>
      <D:resourcetype>
        <D:collection>
          <C:calendar-collection/>
        </D:collection>
      </D:resourcetype>
      <D:displayname>Yep
    </D:prop>
  </D:set>
</D:mkcol>

Deleting a calendar:

DELETE /calendars/pythoncaldav-test HTTP/1.1
Host: example.com
Accept-Encoding: identity

caldav

The version I just released is the very beginning of the project: it has basic functionality, but lacks many things, such as error handling and full support for the protocol. The documentation also needs a lot more work.

Example

I tried keeping the API very simple, and close to what an ORM would be used like, here’s an example:

import caldav
from caldav.lib.namespace import ns

# Principal url
url = "https://user:pass@hostname/user/Calendar"
vcal = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
UID:1234567890
DTSTAMP:20100510T182145Z
DTSTART:20100512T170000Z
DTEND:20100512T180000Z
SUMMARY:This is an event
END:VEVENT
END:VCALENDAR
"""

client = caldav.DAVClient(url)
principal = caldav.Principal(url)
calendars = principal.calendars()
if len(calendars) > 0:
    calendar = calendars[0]
    print "Using calendar", calendar

    print "Renaming"
    calendar.set_properties({ns("D", "displayname"): "Test calendar",})
    print calendar.get_properties([ns("D", "displayname"),])

    event = caldav.Event(client, data = vcal, parent = calendar).save()
    print "Event", event, "created"

    print "Looking for events after 2010-05-01"
    results = calendar.date_search("20100501T000000Z")
    for event in results:
        print "Found", event

Links

I released caldav and its documentation on pypi, and the code is on bitbucket:

Contributions are welcome!

Portrait de blogueurs

J’ai été interviewé pour Portrait de blogueurs hier soir!

Django Debug Toolbar

I wish for two things:

  • That there was some kind of RT function with rss feeds (the only feature I like about twitter)
  • That Django Debug Toolbar is merged in django 1.2+

 

via Planet GNOME

BTW, I can’t believe no one else on Planet Django mentioned it yet!

When a crazy person talks to bots…

Allright, fine, it was me…

I have just discovered that Google Translate can be used through XMPP! Details in this article about translation bots.

The odd thing is, once I have a “contact” in my contact list, I don’t expect it to be a bot (yes, I would suck at being a judge for a Turing test), so I get carried away…

(15:40:36) ion: you're the best, mr. googlebot!
(15:40:36) en2fr@bot.talk.google.com: tu es le meilleur, Monsieur. googlebot!
(15:40:48) ion: i'm not a googlebot!
(15:40:49) en2fr@bot.talk.google.com: Je ne suis pas un robot Googlebot!
(15:41:02) ion: yes you are!
(15:41:03) en2fr@bot.talk.google.com: Oui vous êtes!
(15:41:14) ion: hey!
(15:41:14) en2fr@bot.talk.google.com: hey!
(15:41:21) ion: you're making me angry!
(15:41:22) en2fr@bot.talk.google.com: vous me mettre en colère!
(15:41:36) ion: quit repeating all I say!
(15:41:36) en2fr@bot.talk.google.com: arrêter de répéter tout ce que je dis!

Anyways, have fun with the bots!

The Chatroulette phenomenon

I’m fairly certain that by now everyone knows what Chatroulette is, so I won’t introduce the concept.

I just wanted to mention what has been happening over there in the last couple of months. About 2 months ago, I opened it up, and just saw a few people staring at their webcams, but mostly lots of dudes showing off (or touching) their junk. That was… let’s say unpleasant.

However, since then, I keep seeing these videos of people using chatroulette very creatively, and most of those videos went viral (or somewhat viral), so I think it shows that people are excited about the possibilities offered by chatroulette.

A few examples

Young Rival made a music video, which is pretty awesome.

Everyone now knows Merton

Ben Folds made the Ode to Merton

Then there’s this dude, who looks alot like Nicolas Wright

Anyways, those are only a few of my favorites, and you can find a lot more on youtube

Modifying the regexp for usernames in django-admin

About a month ago, I built a centralized authentication backend using django-roa for my company, AUF. It’s actually a cascading authentication system, since I copy locally (in Django’s own authentication system) the account, once validated.

That was working just fine, until I tried adding some of my users’ local accounts in different groups. The distant usernames follow the format <first_name>.<last_name>, and since Django doesn’t allow that, everytime I would try to save the user edit form in the admin interface, I would get an error message saying that the username format was invalid.

After looking around a bit, I found this solution, which has been working great for me.

from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.contrib import admin

class UserCreationForm(UserCreationForm):
    username = forms.RegexField(label=_("Username"), max_length=30,
            regex=r"^[\w'\.\-]+\s?[\w'\.\-]+$")

class UserChangeForm(UserChangeForm):
    username = forms.RegexField(label=_("Username"), max_length=30,
            regex=r"^[\w'\.\-]+\s?[\w'\.\-]+$")

class UserProfileAdmin(UserAdmin):
    form = UserChangeForm
    add_form = UserCreationForm

admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin)

UVa

A while back, when I was a student in Paris, one of our teachers told us about some project from University of Valladolid (I can’t remember the actual name of the project), it was a contest for programmers, and the goal was to solve as many simple algorithmic problems as possible.

At that time, I thought it was pretty cool, since most of the class was only beginning to understand programming (the class was something like C programming 101), so I used to look at problems and solved them.

I was thinking about that a couple of weeks ago, and I found out that the project still exists, it only changed location/name, which means that I lost my account data (it’s not that bad), but which also means I can keep having fun with it!

You know, by having fun, I mean actually having to think of algorithms and write them myself, you can read this article if you’re not sure what I mean.

Anyway, long story short, the project is UVa Online Judge and it’s awesome!

As a bonus, here’s my solution for the first problem: The 3n + 1 problem

Have fun!

 

// Q100 - The 3n + 1 problem
// http://bit.ly/2aRM6Y
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>

#define MAXNUMBER 1000000

unsigned int cycleLength (unsigned int *known, unsigned int i)
{
  unsigned int length;

  if (i == 1)
    length = 1;
  else if (i < MAXNUMBER && known[i] != 0)
    length = known[i];
  else if (i % 2)
    {
      length = 1 + cycleLength (known, i * 3 + 1);
      if (i < MAXNUMBER)
        known[i] = length;
    }
  else
    {
      length = 1 + cycleLength (known, i / 2);
      if (i < MAXNUMBER)
        known[i] = length;
    }

  return length;
}

int main (int argc, char **argv)
{
  unsigned int *knownCycles;
  unsigned int max, len, a, b, i, start, end;

  knownCycles = calloc (MAXNUMBER, sizeof (unsigned int));

  while (scanf ("%u %u", &a, &b) != EOF)
    {
      max   = 0;
      start = (a > b) ? b : a;
      end   = (a > b) ? a : b;
      for (i = start; i <= end; i++)
        {
          len = cycleLength (knownCycles, i);
          if (len > max)
            max = len;
        }
      printf ("%u %u %u\n", a, b, max);
    }

  free (knownCycles);

  return 0;
}

Fun VoIP use

As I was cleaning up data on my cellphone tonight, I found a video I had recorded about a year ago. I was working -as a side-contract- on a VoIP telephony / PA / bell system for schools. At the lab I was working, I had about 10 phones, 6 speakers (for the hallways), and an intercom (can’t remember why). I was testing the bell system, which was supposed to play a sound on all those devices, from a shell script (actually python, IIRC) that would connect to the asterisk server. The first “beep” is made by all the phones, it’s an alert saying an announce is coming :)
I record one of those tests, and even though it was recorded by my crappy but oh-so-reliable BenQ phone. The music playing is Radiohead’s All I Need.

A little propaganda!

I’ll ba attending those 2 events in the next couple of weeks!

I will be at GeekFest Montreal next March 6-7

 

confoo.ca Web Techno Conference

Introducing django-exportateur

Exportateur?

OK, this article is a bit late, but I think it’s still necessary to properly introduce a new project.

At work last week, I had to write a generic way of exporting a QuerySet to csv, ods, and maybe some other format later on. Since I work at AUF, I frenched up the project’s name.

Why start from scratch?

I’m pretty sure that there already are a few apps that do that, but since I still consider myself kind of new to django, I thought it would be a good learning exercise to write this app myself.

The idea

The files I had to generate needed to have a header that described each column, and the values needed to be clear (no ids, etc.)

I decided to add a method to get the object’s fields (attribute name as well as verbose name), and another one to get the attributes’ values. That’s pretty much it for the Django part.

The last part of the project was to define a generic-enough method to export those fields in the file format we want. The file format is passed as a parameter so that it can be passed directly from the url.

Have a look

The code is now published on code.google.com. Feedback is always welcome.