Unicode och python

UnicodeDecodeError: 'ascii' codec can't decode byte 0x84 in position 1: ordinal not in range(128)

Om du programmerat python känner du säkert igen ovanstående felmeddelande. Roten av problemet är att python har två strängtyper; den ursprungliga str som innehåller en singlebytesträng utan någon vidare information om vilken teckenkodning som använts, och unicode, som är en fullständig unicodesträngtyp.

Det faktum att båda dessa typer finns, fungerar och ser nästan likadana ut gör att en pythonprogrammerare måste vara på tårna hela tiden för att vara säker på vad för sorts data han bollar med — något som tar bort mycket av fördelarna med dynamismen i språket. Annars blir det lätt så att kod som verkar fungerande helt plötsligt krashar om någon stoppar in ett åttabitarstecken nånstans där ingen hade tänkt på att kunde göra det. Och om man inte är disciplinerad är det lätt att man snärjer in sig i en röra av unicode(…) och foo.encode(‘iso-8859-1’). [1]

För lagen.nu 2.0-koden försöker jag använda unicode rakt igenom, så mycket som möjligt, och behandla str som om det vore en bytearray. Det går …sådär. ElementTree ger alltid ifrån sig unicode och man mår bäst om man bara stoppar in unicode i den (även om det går att stoppa in str, men det är inte att rekommendera att använda något med höga bitten satt). BeautifulSoup är unicode-only från och med version 3, vilket är ett stort steg framåt.

Django är dock ett sorgebarn i sammanhanget. Gränssnitten både utåt, mot webbläsaren och innåt, mot databasen, är str, dessutom utf-8-kodat (om man inte ändrat DEFAULT_CHARSET, vilket dock inte är en egentlig lösning), något som är det sämsta av bägge världar. Jag menar, len av en sträng som innehåller ‘räksmörgås’ ska vara 10, aldrig 13, men kolla vad len(u’räksmörgås’.encode(‘utf-8’)) är.

Vad värre är, det går inte att stoppa in unicode överallt heller. De modeller man skapar behöver få sina strängvärden som utf-8-kodade str, annars får man 'Warning: Data truncated for column 'subject' at row 1' och frågetecken i databasen. Åtminstone mot min MySQL-databas, som internt lagrar i utf-8 (tror jag). Är det likadant vad gäller Postgres och SQLite? Vem vet?

Det går väl att lära sig leva med. Sätt upp en barriär mellan django-land och min egen kod, och se till att all str-data kodas om till unicode, och vice versa. Det kanske ordnas innan 1.0, men det är mycket att göra.

Django är dessvärre inte ensam i detta — igår tillbringade jag alldeles för lång tid på att försöka använda email-modulen med unicodesträngar, men den modulen är inte unicodesäker. Simpleparse klarar inte heller unicodeindata. Det finns säkert fler exempel.

Just unicodehantering[2] är ett av de få områdena där jag saknar COM/CLR/Java-världen. Jag menar, multibytetecken funkade smärtfritt i VB6 för typ en miljon år sedan.

På temat unicode saknade jag igår några bra teststrängar för att testa unicodedata med lite exotiskare tecken (allt över U+0255, typ) — utländska motsvarigheter till Räksmörgås, typ. Jag hittade inget direkt, men klistrade ihop något baserat på wikipedias förstasida:

Unicode/UTF-8-test

Som en added bonus innehåller den en hel del BiDi-tester med vad jag tror är korrekt rendering. Jag hade ingen aning om att det var ett så komplicerat ämne, men nu har jag lärt mig en ny HTML-tag. Det är inte varje dag!


[1] Så ser lagen.nu 1.0-koden ut. Ibland blir jag påmind om en kompis som förklarade hur han programmerar C: ”klagar kompilatorn så sätter jag dit en ‘*’, om inte det hjälper byter jag ut den mot ett ‘&'”

[2] Och till en mindre del debugging, även om det har ändrats sedan jag upptäckte Wing IDE

Öka takten sista kvarten, Tidaholm!

Det har inte skrivit mycket på senaste tiden. Delvis beror det på att jag jobbar och pluggar och inte hinner mycket annat, men främst beror det nog på att jag nånstans längs vägen börjat ställa kravet på mig själv att alla blogpostningar ska ha nån sorts mening, leda till nån sorts svar, ha länkar till alla relevanta källo och dessutom inte innehålla så mycket felaktigheter. Inte konstigt att det inte blir något skrivet då. Mitt manifest för sommarens bloggande lyder ”mer ogenomtänkta åsikter, mindre faktakontroll”.

Imorgon skriver jag sista tentan för terminen, Civilrätt 3, dvs immaterial- och marknadsrätt. Det här var ett ämne jag sett fram emot hela utbildningen, men det går inte att sätta sig in i det ämnet på något meningsfullt sätt på bara fem veckor. Särskilt tråkigt tycker jag det är att det resoneras så lite kring grunderna för ensamrätterna och under vilka förutsättningar lagstiftningen faktiskt är ägnad åt att nå de mål som man hoppas uppnå – det har mest varit på nivån ”upphovsrätt uppmuntrar skapande”, följt av en materiell genomgång av paragraferna och direktiven. Jag tycker att tidigare kurser haft en mer genomgripande analys av lagstiftningens mål. Eller så är det bara att jag har haft högre förväntningar på det här ämnet.

Nåväl; studierna har i övrigt flytit på ganska bra under vårterminen (jag fick Ab på C2:an — hurra för mig!) trots eller tack vare mitt halvtidsjobb. Det har stundtals varit ganska tungt att kliva in i södra husen åtta på morgonen och gå hem nio på kvällen, men vafan, det gick ju under den glada IT-eran (fast då var det väl mer tidig eftermiddag till småtimmarna).

Nu när jag får sommarlov från studierna (jag kommer fortfarande jobba drygt halva sommaren) hoppas jag få mer tid över för lagen.nu.
Jag har börjat värma upp pythonkunskaperna lite under helgerna, och har dragit upp riktlinjerna för vad jag vill göra med tjänsten. Det ska bli mer rättskällor (jag har fått tillstånd att publicera alla referat från Domstolsverket, exv, och jag har numera järnkoll på hur och vad man får utnyttja övrigt offentligt material), smartare användning av nyckelord och framförallt wikibaserade annoteringsmöjligheter.

Jag funderar på att i samband med det hela flytta ut tjänsten från mac minin på mitt skrivbord till en riktig serverhall. Har någon ett tips på var man kan få en (ev virtuell) dedicerad server med minst 80 GB disk, alternativt colocation, till ett rimligt pris? Jag behöver rootaccess, eftersom jag tänker köra bleeding-edge-versioner av ett gäng olika verktyg.

I övrigt bäst just nu:

  • Fika: kaffe och apelsinchokladmuffin på 7-11 (min lokala 7-11 frågar inte längre vad jag vill ha när jag kommer in)
  • Mat: 93-öresfrallor på Prisextra (billigt mellanmål)
  • Podcast: Penn Radio (bra morgonlyssning på väg till skolan)
  • Webbplats: Project Aon (”Ensamma vargen”-rollspelsböckerna!)
  • Webbramverk: Django (rent, minimalt och konsekvent)
  • Javascriptwidget: Tiny MCE (löjligt lättintegrerat)
  • Pythonbibliotek: Beautiful Soup (kolla Contributors-listan!)
  • TV: How I Met Your Mother (som Vänner när det var bra)
  • Hardcore: Raised Fist: ”Sound of the republic” (nästan lika bra som ”Dedication”)