Posts Tagged ‘programmering’

Destroy, erase, improve

måndag, augusti 25th, 2008

Nu har det varit tyst här ett tag igen. Jag har ägnat sommaren åt extrajobb, studier inför tentan i C4, samt jobb på nästa version av lagen.nu, som nu börjar närma sig “färdig”-stadiet. På ferenda.lagen.nu finns en betaversion av siten, och de utåt sett viktigaste nyheterna är att formgivningen är fräshare, samt att rättsfallsreferaten nu finns med i fulltext.

Men den stora nyheten bakom kulisserna är att kodbasen till 90% är helt omskriven, och att den nu är öppen källkod under BSD-licensen. Det har tagit lång tid - betydligt längre än det tog att utveckla den ursprungliga versionen - och frågan som inställer sig är om det verkligen var en sån lysande idé? Det finns två förhållningssätt till att slänga gammal kod och skriva om den från scratch — Joel säger att det är en av sakerna you never should do, medans Fred menar att man ska plan to throw one away; you will, anyhow.

De flesta utvecklares första impuls när de sitter med en kodbas som vuxit till en ogenomtränglig röra är att slänga skiten och starta om. Det är för det mesta en dålig idé, inte minst för att det inte finns någon garanti för att man inte hamnar i samma sits tre år senare, när man är klar. Men eftersom det är mycket roligare att bygga nytt än att reparera gammalt skrivs ofta system om från scratch, trots att det skulle varit mycket billigare att steg för steg rensa i det gamla röriga systemet.

Så varför skrev jag då om koden? På grund av glädje och skam. Glädje, eftersom lagen.nu inte har någon affärsplan, några inkomster ellern några krav på företagekonomiskt rationell styrning. Det är ett hobbyprojekt som jag sysslar med för att det är kul, och det har varit mycket roligare att skriva nytt än att rota runt i den gamla koden. Skam, för att det hela tiden har varit meningen att släppa koden fri, och den gamla koden var helt enkelt för dålig för att visa för folk. En kompis har teorin att det här är anledningen till att inte mer kod är öppen — det är helt enkelt för pinsamt.

Beslutet att släppa koden fri, tillsammans med en viss andra systemet-effekt, har gjort att jag i varje steg i utvecklingen har funderat kring det bästa sättet att göra en viss sak. För att slippa skämmas måste man helt enkelt skriva så bra kod som man någonsin kan. När jag skrev det första systemet var jag ganska grön på python, och försökte mest komma på något sätt att göra samma sak. Det tar mycket mer tid att göra rätt än att göra snabbt — särskilt i början – men känslan av yrkesstolthet gör att det är värt det.

Det betyder inte att det inte finns en massa fulheter i koden. Jag är inte superstrukturerad, och inte min kod heller. När jag kommit på ett visst mönster för att göra saker överanvänder jag det gärna, fram till att jag kommer på nästa mönster. Och namngivning samt övrig kodstandard ska vi inte prata om. Men grunden är stabil. Arkitekturen är ganska enkel att förklara, även om det är många (drygt 9000) rader kod. Jag tror att en ny programmerare kan sätta sig in i det hela ganska snabbt, och att det kan vara ett ganska kul system att vara med och bygga på.

Dagens patch

lördag, juni 14th, 2008

Det blir mycket RDF i lagen.nu 1.5. Och det blir mycket användande av RDFLib. Efter att ha hittat finfina instruktioner om hur man får biblioteket - inklusive SPARQL-parser - att snurra under windows har jag gett mig på min pet peeve i n3-serialiseringskoden, nämligen dess ovana att definera egna anonyma namespaceprefix. Normalt serialiserar den nämligen n3-formatet något i stil med såhär:

@prefix _8: http://lagen.nu/.
@prefix _9: http://lagen.nu/1962:700#.
@prefix dct: http://dublincore.org/documents/dcmi-terms/.
@prefix rinfo: http://rinfo.lagrummet.se/taxo/2007/09/rinfo/pub#.

_8:NJA_2005_s_878 dct:identifier "NJA 2005 s. 878 (NJA 2005:95)";
rinfo:lagrum _9:K29P7;
rinfo:rattsfallshanvisning _8:NJA_1996_s_63,
_8:NJA_2000_s_421;

Men nu blir det det oändligt mycket mer läsbara:

@prefix dct: http://dublincore.org/documents/dcmi-terms/.
@prefix rinfo: http://rinfo.lagrummet.se/taxo/2007/09/rinfo/pub#.

 <http://lagen.nu/NJA_2005_s_878> dct:identifier "NJA 2005 s. 878 (NJA 2005:95)";
     rinfo:lagrum <http://lagen.nu/1962:700#K29P7>;
     rinfo:rattsfallshanvisning <http://lagen.nu/NJA_1996_s_63>,
         <http://lagen.nu/NJA_2000_s_421>;

Här är patchen:

C:\Users\staffan\tmp\rdflib-2.4.0\rdflib>diff -u syntax\NamespaceManager.py~ syntax\NamespaceManager.py
--- syntax\NamespaceManager.py~ 2007-04-04 22:05:32.000000000 +0200
+++ syntax\NamespaceManager.py  2008-06-14 21:36:32.606307200 +0200
@@ -59,8 +59,7 @@
namespace = URIRef(namespace)
prefix = self.store.prefix(namespace)
if prefix is None:
-                prefix = "_%s" % len(list(self.store.namespaces()))
-                self.bind(prefix, namespace)
+                raise Exception("Prefix for %s not bound" % namespace)
self.__cache[uri] = (prefix, namespace, name)
return self.__cache[uri]

Den som förstår RDFLib bättre kan säkert få till samma effekt utan att patcha källkoden genom att subklassa NamespaceManager och trycka in den i kedjan någonstans, men mina försök till det misslyckades.

Fyra snabba

tisdag, februari 12th, 2008

Det verkar som jag är inne i en bloggningsperiod. Men långa utläggningar har jag inte tid med, jag måste korta ner en Techworld-krönika från (just nu) 4356 tecken till 2600 innan jag får gå och lägga mig. Vi får ta det snabbt:

Kort är det nya svarta: Det började med jQuerys fokus på att förkorta vanliga javascriptidiom till en eller ett par tokens, fortsatte med Paul Grahams sneak preview på Arc och dess galet kompakta uttrycksfullhet, och idag liknar Steve Yegge babbliga programmerare (och språk) vid tvååringar. Juristmetafor: EG-rätt = Java, Handelsbalken = Lisp.

Lagar och kod: En sak som är lite frustrerande är att jag efter tre års juriststudier fortfarande inte har bra svar på varför lagen är så svårtolkad och oförutsägbar. Precis i början av studierna, när jag fortfarande utgick från det tankesätt som jag tillägnat mig som programmerare, undrade jag om man inte kunde ha nån sorts enhetstester för paragraferna, så att man kunde utvärdera om lagen uppfyllde de syften den skapats för. Bennet Haselton har utvecklat ett förslag längs samma linjer som han tror skulle kunna lösa de problem han stött på i amerikanska underrättsdomstolar. Problemställningen saknar helt uppenbart inte verklighetsförankring, men är det en bra lösning? More to the point, är det en genomförbar lösning? Jag drar paralleller till den kurs jag läser just nu, och dess diskussioner om olika rättskällors legitimitet. Den rättskälla som för de flesta är the rättskälla, lagstiftningen, behöver bara ha en yttre legitimitet (vara utfärdad av någon med folkets eller vapenmaktens mandat) — en eventuell inre legitimitet (i betydelsen fungerande systematik, exakthet, logisk konstistens, fullständighet) är bara en nice-to-have. Åtminstone så länge avsaknaden av inre legitimitet inte har någon bäring på den yttre legitimiteten (dvs så länge väljarna inte kräver lagstiftning vars faktiska utformning är begriplig).

Ska vi ha bättre spärrar — eller inga? Utredningen Musik och film på internet - hot eller möjlighet? (Ds 2007:29), med dess förslag att ålägga ISP:er att stänga av fildelare, har väl (milt sagt) inte blivit så väl mottagen i bloggosfären, och har även blivit mer genomgående kritiskt granskad. På andra sidan Atlanten ställs också krav på att ISP:er ska “ta sitt ansvar” för att hejda olaglig fildelning. Nicholas Weaver föreslår, på bästa code-is-law-manér, en bittorrentspecifik lösning för att spärra just bara den olagliga fildelningen, som han menar är en mer ändamålsenlig lösning som minimerar “collateral damage”. Min spontana tanke är att en sådan spärrning - om den implementeras - kommer att påskynda utvecklingen av mindre darknets som är ännu svårare att övervaka eller stoppa. Och gör existensen av en mer ändamålsenlig (”bättre”) spärr det svårare att argumentera för ett övervaknings- och filtreringsfritt Internet?

Alla måste läsa: Kevin Kelly, Better Than Free.

Slutligen: Hela förra veckan gick tankeverksamheten på halvfart. Inte bra när man har mycket att göra. Så jag fick jobba sent och hann inte ut och springa något. Igår snodde jag åt mig några timmar och körde nästan en halvmara runt kungsholmen och söder. Idag har jag haft träningsvärk och ett helt fantastiskt flyt på tankarna. Lärdom (som jag lyckas glömma bort då och då): Träning är inte en hobby man kan göra i mån av tid, utan en förutsättning för att man ska orka med allt annat. Ungefär som frukost (fast svettigare).

Oj, det blev visst fem snabba. Jag är så otroligt busy att jag inte hinner kontrollräkna.

Keep It Simple, Staffan

måndag, september 10th, 2007

Mycket med det mesta nu. Några deadlines som närmar sig med oroväckande hastighet, och det jag tänker mest på är den föreläsning jag ska hålla på specialkursen Experimentell immaterialrätt om en vecka. Temat för kursen är “Immaterialrätten på internet”, och rubriken på min föreläsning är “Tekniken på Internet”. Det blir lite paragrafer och mycket trebokstäversförkortningar.

Jag satt halva söndagen och försökte strukturera upp vad jag ville säga. Jag vill på något sätt förmedla en insikt i vad digital information och öppna nätverk innebär, den där outtryckbara kärnan från vilken man kan härleda allt annat. Den solida grund som gör att man kan titta på ny teknisk kunskap och förstå hur den ska sorteras in och relateras till allt annat, vilka liknelser som funkar och vilka som är missvisande, problem den löser och problem den skapar, hur den borde regleras (eller inte), och så vidare. Så jag satt i några timmar och försökte formulera en mening om digitalisering som skulle kunna förklara allt det där.

Men allvarligt, det är få förunnat att kunna förmedla kunskap på det sättet. Efter att ha snärjt in mig i högtravande formuleringar om informationens sanna innersta väsen försökte jag sätta mig in i hur det skulle uppfattas av en åhörare. “Osubstansiellt flummande” blev omdömet.

Så jag raderade texten och började om med inriktning på handfasta kunskaper. 10 minuter om hur man digitaliserar text, ljud, och bild, 10 minuter om komprimering, 10 minuter om grundläggande internet, 10 minuter om tillämpningar som web och fildelningsprotokoll, 5 minuter om DNS… Mindre ambitiöst, men ger förmodligen mycket mer behållning.

I övrigt är jag sjukt sugen på att koda lite. Det blev inte så mycket av det i sommar, och jag har abstinens. Någon gång i slutet av september kan jag förhoppningsvis få tid över till lite mysprogrammering. Utvecklingsversionen av Django har äntligen fått unicodestöd, och jQuery verkar vara ett smutt javascriptramverk nu när mochikit verkar ha ramlat i glömska. Vi får se vad som händer.

Lägesrapport

torsdag, augusti 23rd, 2007

Liten uppdatering om vad jag håller på med:

Träning: Har börjat komma igång så smått efter kalmar, målsättningen är fyra lättare pass i veckan (ett simpass, två löppass och ett långpass på cykeln) med mycket fokus på bra teknik.

För löpningen innebär det att öka stegfrekvensen till ca 180 steg i minuten (Jag har några podrunner-mixar med lämplig BPM i lurarna för att hålla takten vilket hjälper mycket - synd bara att musiken är så trist) och se till att landa på fotsulan (inte hälen) med foten under kroppen (inte framför). 180 steg i minuten är vansinnigt mycket fortare än de kanske 150-160 jag brukar springa med, men jag kan redan känna att det här är mindre slitigt för lederna och mer slitigt för flåset.

För simningen innebär det att lära mig växelvis andning, dvs andas var tredje simtag på omväxlande höger och vänster sida. Tidigare har jag andats varannat simtag, alltid på höger sida, och det är lite svårt att få in så mycket luft i lungorna den korta sekund munnen är ovan vattenlinjen att det räcker för tre simtag. Idag skedde dock någon form av litet genombrott och jag kunde köra 400 m oavbrutet i en lugn rytm utan att syret tog slut. Försöken att lära mig voltvändning är dock än så länge fruktlösa.

För cyklingen innebär det att få till ett bra rundtramp, dvs att utnyttja benens alla muskler till att inte bara trycka ner pedalen (mellan klockan 2-5 om man tänker sig vevpartiet som en urtavla) utan även dra den bakåt (5-7), uppåt (7-11) och slutligen trycka framåt (11-2). Det övar jag främst genom att klicka ur ena skon ur pedalen och dra runt cykeln enbart med andra foten under några minuter (det är sjukt tungt!). Det svåra är att få jämnt tryck och hastighet så att inga “döda punkter” finns på hela varvet. Jag försöker även öka kadensen - det rekommenderas att man trampar 90 varv / minut. Jag har ingen kadensmätare så jag har ingen aning om vad jag ligger på, men förmodligen alldeles för lågt.

Jobb: På måndag slutar min semester från min huvudsyssla som amanuens på IRI (vars webbplats för övrigt numera är uppfräshad, XHTML-validerad, allmänt semantisk och mikroformatbeströsslad). Hösten lär bjuda på en hel del löpande administrationsarbete, men också arrangemang av konferenser och liknande evenemang. Boka den 29 november för konferensen “Den rättsliga informationsförsörjningen: Säkerhetskrav?” redan nu!

Men jag har ett gäng sidouppdrag av varierande omfattning. Under sommaren har jag jobbat lite med det offentliga rättsinformationssystemet (som jag även var aktiv inom under förra hösten) med att skriva lite skön pythonkod som genererar RDF och XHTML2-versioner av de (konsoliderade) författningar som ingår i SFS. Lite samma som gamla lagen.nu-koden, men den här gången med en kodkvalité som jag faktiskt inte behöver skämmas över. Bland annat har jag därigenom lärt mig att använda Genshi för XML-generering medelst templates - inte alls dumt. Koden kommer förhoppningsvis snart göras tillgänglig under någon lämpligt öppen licens, tillsammans med resten av rättsinfoprojektets kodbas.

Det finns några ytterligare saker i pipen, bland annat medförfattande av en lite mer akademisk artikel om ett spännande ämne, en permanent post som krönikör i en större branschtidning, och en föreläsning på en av juridiska programmets specialkurser. Mer detaljer kommer när det börjar närma sig slutförandet. I övrigt försöker jag hålla nere på extraknäcken så att jag kan fokusera på…

Studier: Har tyvärr varit lite eftersatta under våren. Nu är det bot och bättring som gäller. Skatterätt (som jag inte direkt sett fram emot, men däremot alla mina kompisar som vill göra smarta avdrag) och förvaltningsrätt (vilket ska bli märkligt kul) är det som gäller under året. Jag ska även tenta av de två kurser jag har släpande (fastighetsrätt och processrätt). Banne mig.

Sen är det bara teoretiska terminen (med ffa rättshistoria och allmän rättslära), specialkursterminen (där jag ska försöka begränsa mig till två kurser från ett betydligt större smörgåsbord) och examensarbetet (där jag kommer på ett nytt ämne i veckan som jag vill skriva om) kvar innan jag blir jur kand. Nu är det bara hemvägen (mindre än hälften) kvar, två år. Det är ju ING-EN-TING!

Culpatic programming

onsdag, februari 23rd, 2005

In the legal world, there is this latin term “culpa”, which translates roughly to “carelessness” or “neglience”. The term does not seem to be used in US Law, but I’m guessing a similar concept still exists in all Common Law countries (it might be worth mentioning to the casual Google refereant that this post is written based in my understanding of swedish law — if you’re in some other jurisdiction you should take this with an even larger grain of salt).

The concept of culpa, or rather careless behaviour, is very important when it comes to assessing whether a certain harmful action (or sometimes inaction) by a person should make that person liable for damages. The rules differ somewhat if the two parties were in a legal agreement of some kind, but basically — if you cause harmful effects, you’re generally worse off if it was due to carelessness than if it was by accident (”casus”).

For example, if a supplier did not deliver his goods to the customer at the agreed time and place, and this was harmful to the customer in some way, the supplier is more likely to be liable for damages if the reason for the failed delivery was due to him forgetting about it, as opposed to there being a unforeseeable traffic jam that prevented him from reaching the delivery place on time.

To determine wheter a particular action should be categorized as casus or culpa, a court need to have some sort of guideline as to what is generally considered to be careless in the context of the harmful action. In some cases (such as traffic, or working environments), there are rules that more or less spell out what is considered careless. In the absence of those rules, courts generally observe what level of carefulness that is considered adequate by those proficient in the profession or trade.

In the programming world, there’s a whole lot of “culpatic programming” going on — proficient developers know about appropriate steps to ensure at least some level of quality in their delivered products, ranging from design methologies to source code management to customer involvement to established QA techniques. They also know that these steps often are not followed — for whatever reason. The result is buggy software that cost time, money and sometimes lives.

Yet, the fact that many programs and systems are carelessly written ise rarely discussed — most of the time, it is observed that bugs will happen, a EULA or other agreement that absolves the company of liabilities due to bugs in the code is slapped on, and that’s the end of that.

While is true that it’s impossible (in any practical sense) to write bug-free programs, it is possible to make a meaningful distinction between bugs cased by carelessness (”culpa” bugs) and bugs cased by accident (”casus” bugs). The intented usage for the system will probably affect how the distinction is made (a off-by-one bug might well be determined to be a “casus” bug in a admin UI for a in-house CMS, but is probably a “culpa” bug in the firmware for a electronic pacemaker). This also means that software that, when written, is likely to capture a mass market (such as the RPC server in the next Windows version) could and should be held to a higher standard than software written on a hobby basis, when it comes to determine carelessness.

Often, when the issue of software liability is raised, the discussion is cut short by the observation that software will always have bug, and that some of them will cause disastrous effect. It’s also observed that there is a point in software development where the cost of finding and fixing the remaining bugs is larger than what the customers are prepared to pay, and if we make the law demand software developer liability, no programs (particularly open source ones) will get released. While it’s true, it’s a all-or-nothing argument. As a (semi-retired) developer, I’ve caused my fair share of bugs in my time. Many of these were casus bugs, but some were culpa bugs, bugs that I would not have created had I followed adequate development procedures. It’s the latter sort of bug I’m talking about — the ones that are technologically AND economically feasible to eliminate, but developers lack incentive to do so (other than pride of craftmanship).

One large problem is that very few are qualified to determine whether a bug is culpa or casus. Then again, very few are qualified to determine if a certain food handling procedure is adequate or neglient, or wheter a car’s failing braking system was carelessly designed or not. The legal system still demands that we make a destinction between culpa and casus in these cases, and does not allow the food or car industry to sell their products with attached general disclaimers that frees them from responsibility. Wheter enough care was taken is determined by experts in the respective fields. For the software case, this will mean letting independent parties review the code and particular the conditions of the bug. This will, in many cases, be expensive, but so are the problems that software bugs cause.

Part 7: Regression testing

söndag, december 19th, 2004

(A series of blog posts about the tech behind lagen.nu. Earlier parts are here: first, second, third, fourth, fifth and sixth)

Like most developers that have been Test infected, I try to create regression tests whenever I can. A project like lagen.nu, which has no GUI, no event handling, no databases, just operations on text files, is really well suited for automated regression testing. However, when I started out, I didn’t do test-first programming since I didn’t really have any idea of what I was doing. As things solidified, I encountered a particular section of the code that lended itself very nicely to regression testing.

Now, when I say regression testing, I don’t neccesarily mean unit testing. I’m not so concerned with testing classes at the method level as my “API” is really document oriented; a particular text document sent into the program should result in the return of a particular XML document. Basically, there are only two methods that I’m testing:

  • The lawparser.parse() method: Given a section of law text, returns the same section with all references marked up, as described in part 5.
  • Law._txt_to_xml(), which, given a entire law as plaintext, returns the xml version, as described in part 4

Since both these tests operate in the fashion “Send in really big string, compare result with the expected other even bigger string”, I found that pyunit didn’t work that well for me, as it’s more centered around testing lots of methods in lots of classes, where the testdata is so small that it’s comfortable having them inside the test code.

Instead, I created my tests in the form of a bunch of text files. For lawparser.parse, each file is just two paragraphs, the first being the indata, and the second being the expected outdata:

    Vid ändring av en bolagsordning eller av en beviljad koncession
    gäller 3 § eller 4 a § i tillämpliga delar.

    Vid ändring av en bolagsordning eller av en beviljad koncession
    gäller <link section="3">3 §</link> eller <link section="4a">4 a §</link> i tillämpliga delar.
  

The test runner then becomes trivial:

def runtest(filename,verbose=False,quiet=False):
    (test,answer) = open(filename).read().split("\n\n", 1)
    p = LawParser(test,verbose)
    res = p.parse()
    if res.strip() == answer.strip():
        print "Pass: %s" % filename
        return True
    else:
        print "FAIL: %s" % filename
        if not quiet:
            print "----------------------------------------"
            print "EXPECTED:"
            print answer
            print "GOT:"
            print res
            print "----------------------------------------"
            return False
  

Similarly, the code to test Law._txt_to_xml() is also pretty trivial. There are two differences: Since the indata is larger and already split up in paragraphs, the indata and expected result for a particular test is stored in separate files. This also lets me edit the expected results file using nXML mode in Emacs.

Comparing two XML documents is also a little trickier, in that they can be equivalent, but still not match byte-for-byte (since there can be semantically insignificant whitespace and similar stuff). To avoid getting false alarms, I put both the expected result file, as well as the actual result, trough tidy. This ensures that their whitespacing will be equivalent, as well as easy to read. Also, a good example of piping things to and from a command in python:

def tidy_xml_string(xmlstring):
    """Neatifies a XML string and returns it"""
    (stdin,stdout) = os.popen2("tidy -q -n -xml --indent auto --char-encoding latin1")
    stdin.write(xmlstring)
    stdin.close()
    return stdout.read()
  

If the two documents still don’t match, it can be difficult to pinpoint the exact place where they match. I could dump the results to file and run command-line diff on them, but since there exists a perfectly good diff implementation in the python standard libraries I used that one instead:

    from difflib import Differ
    differ = Differ()
    diff = list(differ.compare(res.splitlines(), answer.splitlines()))
    print "\n".join(diff)+"\n"
  

The result is even easier to read than standard diff output, since it points out the position on the line as well (maybe there’s a command line flag for diff that does this?):

[...]
      suscipit non, venenatis ac, dictum ut, nulla. Praesent
      mattis.</p>
    </section>
-   <section id="1" element="2">
?                   ^^^

+   <section id="1" moment="2">
?                   ^^

      <p>Sed semper, ante non vehicula lobortis, leo urna sodales
      justo, sit amet mattis felis augue sit amet felis. Ut quis
[...]
  

So, that’s basically my entire test setup for now. I need to build more infrastructure for testing the XSLT transform and the HTML parsing code, but these two areas are the trickiest.

Since I can run these test methods without having a expected return value, they are very useful as the main way of developing new functionality: I specify the indata, and let the test function just print the outdata. I can then work on new functionality without having to manually specifying exactly how I want the outdata to look (because this is actually somewhat difficult for large documents), I just hack away until it sort of looks like I want, and then just cut’n paste the outdata to the “expected result” file.

Part 3: Understanding what was fetched

onsdag, december 15th, 2004

(Earlier posts in this series: here and here)

There are a lot of ways to extract data from a HTML file. You can do simple string searching (by the way, why is the python documentation for basic string objects hidden under the non-descript heading “Sequence types”, and why is there no reference to that part of the documentation from the separate string module, which hardly does anything?) and rexep munging, or you can use more sophisticated HTML parsers. Funnily enough, there are two of these in the Python standard library, and both of them are callback based — why no tree-based interface? If the HTML code is modern and well-formed, you can even use a vast array of XML tools (and if it’s not, you can fix it with HTML Tidy).

I ended up using the BaseHTMLProcessor approach from Dive Into Python., which has a whole chapter devoted to the art of HTML parsing. Basically, you subclass BaseHTMLProcessor, implementing callbacks for various tags, which are called as these tags are encountered in the document. Your class is responsible for keeping track of whatever state (ie what depth you are in the document, what tags were encountered before this one, and so on) that needs to be kept.

There are some things that are cumbersome with this approach. For example, automatic HTML entity resolving would be good. The HTML fragment “<h1>r&auml;ksm&ouml;rg&aring;s</h1gt;” represents a single header with the string “räksmörgås” (a common test phrase for swedish programmers), and so it should only result in three callbacks: start_h1, handle_data (which should be called with the string “räksmörgås“), and end_h1.

Instead, the following callbacks are called:

  • start_h1
  • handle_data (called with the string ‘R‘)
  • handle_entityref (called with the string ‘auml‘)
  • handle_data (called with the string ‘ksm‘)
  • handle_entityref (called with the string ‘ouml‘)

…you get the idea. There exists a mapping that helps with the entity resolving, but for the HTML case, this could have been solved at a lower-level stage.

Still, for the parsing problems I have, the callback-based/keep-your-own-goddam-state-approach works. Most of the time I’m just concerned with finding the elements in a table, meaning I have to keep track of what cells I’ve seen and when a new table row starts, things like that. As I go along, build up a list of mappings or something similar, and then just use that list once done. The calling code gets quite nice and simple:

cl = SFSChangelogExtractor()
cl.feed(open("downloaded/lawinfo/%s.html" % self.basefile).read())
for c in cl.changelog:
    if c.item('SFS-nummer') == current_transitional_id: ...
  

(Note that the ‘c’ object here is not a standard dictionary, but a mapping-ish object that also keeps track of the order keys have been inserted. That’s why it’s c.item(’SFS-nummer’) and not c[’SFS-nummer’]. That, and the fact that I was too lazy to implement the special methods needed to do a proper Duck Typed dictionary.)

The one exception is the problem of finding all the plaintext in a law text like this one, but it’s even easier: Just increment a counter whenever a <pre> tag is encountered, decrement it when seing </pre>. In handle_entityref and handle_text, just check if the counter is > 0 and if so, append the text to a StringIO object.

Lagen.nu behind the scenes

måndag, december 13th, 2004

Now that lagen.nu has been out for some time, it might be a good idea to write down what I’ve learned from it so far, in blog form. Much of the discussion will be centered around python, a language I’m far from proficient in, but it’s possible that someone will learn at least something from it.

First, take a look at this post that explains what lagen.nu is, from a user perspective.

This post is about how the site is produced. When I started out, I had no clear idea of what I wanted to do, other than to download the text of all swedish laws and convert it to some sort of nice HTML. I knew I wanted to do as much as possible with static HTML files, and I had a hunch that XML would be involved in some way.

So, essentially, the code only needs to run off-line, with no GUI required.

I thought about doing this in C#, since it would be a good experience building project in a language for which expertise is highly sought after. But since I’m no longer programming for food (actually I am, for another four days, but still), I took the opportunity to do it in python, a language which I’ve always liked but never become friends with.

From a high level, the code does the following:

  • Finds out what laws are available
  • Downloads the law text HTML documents
  • Converts the text to XML
  • Transforms the XML to HTML

There are some extra steps involved in creating the front page, RSS feeds, and handling the verdicts database, but these are the main steps.

The result of the program is a tree with static HTML files, ready for deployment.

I started out by looking for a good Python IDE. I did not find it, and settled for Emacs with python-mode.

Once set up with a recent version of python-mode, properly configured, I had a nice light-weight development environment. Here’s my minimal configuration (this goes into your .emacs file):

(autoload 'python-mode "python-mode" "Python Mode." t)
(add-to-list 'auto-mode-alist '("\.py'" . python-mode))
(add-to-list 'interpreter-mode-alist '("python" . python-mode))
(setq py-python-command "C:\Python23\python.exe")
  

My code lives in classes, and to test things out, I have code at the end of the main code file that looks sort of like the following:

if __name__ == "__main__":
    vc = VerdictCollection()
    vc.get(2004,refreshidx=True)
  

(That is, if I want to test the get method of the VerdictCollection class). To test the code, I just press C-c C-c in the python editor window. The entire python buffer gets sent to the python shell, and the last part (after if __name__ == “__main__”:) executes.

Things that are good about this environment:

  • Free, in both senses of the word
  • The intendation support really works, which is quite important with python
  • Reasonably fast edit-run cycle
  • The interactive python shell

Things that are bad:

  • I can’t debug stuff. It seems like it should be possible, but I have no pdb.exe, which seems to be a requirement. In particular, it would be nice to be able to automatically start debugging when an unhandled exception is raised.
  • Copy and paste from the *Python* buffer has character set problems. For example, if my code outputs a § sign, and I cut’n paste it into another file, emacs will complain:
    These default  coding systems were tried: 
    iso-latin-1-dos
    However, none of them safely encodes the target text.
    This is bogus, since the § sign is perfectly legal in latin-1.

I use the standard python.org distribution of Python 2.3 (I haven’t gotten around to upgrading to 2.4 yet), not the ActiveState one. I tried it, and like the fact that the win32com module is bundled, but the python.org version is a leaner download and has a more usable HTML help application (particularly the good index).

To get a grip of how to do things with python, I’ve used the online version of Mark Pilgrim’s Dive Into Python, as well as the Python cookbook. This, together with the reference manual, (the eff-bot guide to) The Standard Python Library and Text Processing in Python has been all I need so far.

Bruce Eckel on Generics and erasure

söndag, september 26th, 2004

Bruce Eckel has his third article (earlier articles here and here) on the role of erasure in Java 5.0 Generics. Complicated subject, at least for me who hasn’t developed anything with either .Net or C# generics, but as usual with Bruce, very well written.