Armed with a text editor

mu's views on program and recipe! design

July 2007

Editing Appreciated Posted 2007.07.09 18:23 PDT

Nis Martensen, who has undertaken to translate my CairoTutorial into C, found several typos and a source code misalignment. (The latter possibly introduced when I fixed the real error Mark spotted.) I fixed the typos and updated my code display macro to work with tagged lines of code so it should be much less brittle against future code updates. Thanks, Nis!

(0 Comments ) (0 Trackbacks) cairo python

Fixing im-ja Posted 2007.07.06 23:16 PDT

My favorite Japanese input method for gtk+, im-ja, broke when I updated to Debian's gtk+ 2.10 packages. Since there's no upstream activity to speak of (much less new packages), and I can't seem to find this on the web anywhere else, here's the solution I eventually found. No doubt there's a better one out there that updates the package to use the new debhelper support for gtkimmodules to create this file, but I made mine by hand:

% cat /usr/lib/gtk-2.0/2.10.0/immodule-files.d/imja.immodules 
# edited by hand
"/usr/lib/gtk-2.0/2.4.0/immodules/im-ja.so"
"im-ja" "Japanese" "gtk+" "/usr/share/locale" "ja"

I had tried compiling a new version of the existing package that would go into the 2.10.0 immodules folder, but that didn't help. When I wired that version up with the slight mode to the above file, it crashed applications that tried to use it. But the original im-ja package is still kicking!

(0 Comments ) (0 Trackbacks) debian gtk+ japanese

April 2007

ReReplayGain Posted 2007.04.07 20:16 PDT

After ending up with too many MP3 files without proper ReplayGain information, and knowing that mp3gain doesn't suit my needs quite right, I went jonesing around in GStreamer once again. Today was my lucky day, though; René Stadler had created a GStreamer element which calculates ReplayGain.

In what's starting to feel usual, Debian doesn't have up to date versions of the software I want to use in either testing or unstable, but this hasn't prevented the maintainer from packaging what I want to use and mirroring it in experimental. After downloading and installing it, I was good to go. First I put together a command-line example of the process, to make sure I knew what was required. Then I munged it into a plugin for Quod Libet.

There's still something fishy about it, as MP3s which I have previously found peak values for above 1.0 are now being reported capped to 1.0; Ogg Vorbis files, on the other hand, correctly exceed this cap and run presumably all the way to 2.0. I hope to clarify my understanding of this probable GStreamer bug shortly, as other than that all values match what I've seen before. I'm quite pleased the results of tonight's work.

(4 Comments ) (0 Trackbacks) gstreamer python quodlibet

March 2007

Script your build, no really! Posted 2007.03.20 20:05 PDT

Thanks Mark Edgington for finding and alerting me to an error in the code behind my Cairo Tutorial. Somewhere between when I originally wrote it and used it to generate it, and when I uploaded it, I introduced an ordering problem that caused the Mask diagram to fail to draw. The trivial difference just required moving the call to super(Mask, self).__init__(*args) to the end of Mask.__init__. For anyone reading the tutorial: don't fear; no informative parts have changed.

This simple error has been sitting there since I originally wrote the code some nine months ago. Even a small project like this tutorial could have benefited from continuous integration.

(0 Comments ) (0 Trackbacks) cairo python

October 2006

Plugging in to Epiphany Posted 2006.10.21 13:13 PDT

I recently decided to try out Epiphany for real after the umpteenth time Firefox went haywire when my gtk theme changed. As a base browser, the only things it has going for it are the ability to drag tabs around, and the tag-based bookmarks system.

On the downside, using that tag-based bookmarks system means starting over when you have hundreds of poorly categorized bookmarks like I did. I'm still not sure if I like it, but it's definitely neat.

On the plus side, Epiphany can be tweaked with Python extensions. In particular Stefan Stuhr's Only One Close Button is a blessing to those of us who don't like scrolling through tabs.

With this in mind, I set out to fix a problem I've been experiencing. One of the sites I visit takes user submitted content, including a link and a comment. Lots of submissions include a link in the comment field. However in order to preserve their table layout without having it overflow, the site embeds U+200B Zero-Width-Space characters into the shown text. When I select the text and paste it to a new tab, the url will contain a '%E2%80%8B' substring (URL-escaped UTF-8 encoded U+200B) which invalidates the destination, and tends to yield either a 404 or a redirection.

I wrote up a simple extension based on the tutorial, but debugging it was a real pain. My initial session of epiphany was running somewhere with no stdout or stderr. My first draft of my extension had several errors which resulted in thrown exceptions. A bug with Epiphany causes it to fail to exit properly when Python extensions throw exceptions. It was not only failing to reload my extension, but when I thought I was running Epiphany in a terminal, it was really resuming the existing session. Let this be a lesson to Epiphany Python extension developers: be willing to kill your running Epiphany process!

After figuring that out with the help of jfr on #epiphany, I was then able to complete the extension handily. It's not ideal: it causes a second automatic page load to happen, and going back to the page with the zero width space in the URL will again trigger the redirect. But it's good enough for me. If anyone else wants it, either to use or to fix, you can get it from EpiphanyExtensions.

(0 Comments ) (0 Trackbacks) epiphany python

Lament of the Python Developer Posted 2006.10.12 12:22 PDT

I love working in Python. When I was first coming from Perl everything felt weird. Now I can't imagine going back voluntarily. However there are a few laments that come up time and time again to trouble me, the Python using developer.

Cross-version compatibility

The developers of Python have a pretty rigorous backwards-compatible culture, but the actual implementation leaves something to be desired. While many modules, especially those outside of the standard library, but maintained by those who develop Python, are able to be compatible across many versions, the recent new Python 2.5 managed to create two completely separate incompatibilities in Quod Libet and mutagen. As Martin v. Löwis said, someone always notices. If only they had put as much thought into the changes that hit us as they seem to be putting into whether floating point +0.0 and -0.0 can be distinguished.

Quality of bindings

Every binding of a library implemented is implemented separately, and generally by different authors. This leads to python modules that feel wildly different, from different naming conventions, to support for pythonic methods. Support for pythonic methods range themselves from supports iteration to the right mixture of functions and objects with methods. Sometimes collections of similar modules group behind a common API such as the DB API.

When I first started using python, I happened to pick Pygame, a very easy to use binding. It was well documented. The parts you needed regularly were small enough to fit in your head. There were helpers in the right places. It accepted reasonable duck-typing in convenient places, such as accepting any 4-element list or tuple where a pygame.Rectangle was going to be used, implicitly upcasting it.

By contrast, recently I've tried to find a good binding for working with subversion, and have had poor luck. The initial binding, a poorly documented SWIG wrapper, was very tied to a low level C interface. Nobody using the python bindings would want to deal with the APR directly. More recently, pysvn seemed to address this. The functions seemed to expose the right level to let me get my work done.

My Ideal PySvn

After working with it for a couple days, however, I've changed my mind: pysvn still has a long way to go. I'm going to present a couple steps that would bring pysvn closer to my idealized version, shamelessly ignoring that implementing it would require many API-incompatible changes.

While trying write a simple subversion browser, there are two road blocks I keep bumping into.

  1. Revisions are way too hard to use.
  2. Dictionaries of attributes are filled with inconsistent names.

I'm not sure which of the above road blocks bothers me more. On the one hand, the Revision object reads like a straight translation of a C struct with a union inside it. This allows it to represent any of several kinds of revision. But I would contend that it should just accept simple python types.

For simplicity, the constructor should accept these, and any function that requires them should run them through the constructor as necessary. For an attempt at bonus points the constructor could also accept strings like '137' or '1986-01-28 17:39:13.620000' in place of integers or time objects, but it's probably better not to accept those. Better yet, these objects should always be used, and the Revision object should be dropped from the Python interface.

On the other hand, inconsistent names in the properties dictionaries are really hard to keep straight. The info() call returns an Entry object, with attributes including commit_author commit_revision commit_time kind name revision url. The info2() call returns items with attributes including last_changed_author last_changed_rev last_changed_date kind rev URL. Note that the commit prefix became last_changed, the time suffix became date, revision became rev, url became URL, and name disappeared. The log() and ls() calls suffer similar transformations, although the amount of information each contains is smaller.

I'm willing to assume that the actual subversion API is similarly fickle, and that the pysvn authors didn't create this mess, but I really want it to be cleaned up. I'd like to get an object, say a subclass of a mythical PySvnItem, which knows its url and name and revision, and can look up various other items that may not have been returned by the corresponding C API call when you access the appropriate attribute so I don't have to worry about which call provided the original PySvnItem. And the names of these attributes should be normalized so I don't have to worry about last vs last_changed vs commit prefixes.

Bugs

No lament is complete without mention of at least the one latest bug that delayed some work. In this case it was pysvn's diff() method, which fails with a weird C++ error if you pass it revisions as positional arguments. Peter found that named arguments work fine, so it's no longer in my way.

(0 Comments ) (0 Trackbacks) pysvn python

September 2006

Mmm, Proprietary Serviceware. Posted 2006.09.30 09:22 PDT

So many things I forego writing about to fill up your feed, but here's one that I just have to. A while ago I worked on a program I was calling tansei. The eventual goal was to be a personal planet-style feed aggregator in an application instead of a browser window. But I got tired of it after some of the simplest bits of it fought me for too long. And as usual when I write software, I distracted myself with less important parts of it first - in this case trying to render all sorts of crappy html the way I wanted it.

So finally a few months ago Joe tells me liferea has a compact view which does exactly what I want...at least when it manages to pull the entries separately. And that means I no longer have to write the rest of the program, so I'm happy. Mostly. I don't actually like liferea all that much. The interface is somehow clunky in ways I can't put my finger on. The one I can is where it fails to act like another application which doing something weird - if, like pan's error window, liferea would put a close window button next to the mark-items-read button, I'd stop accidentally refreshing everything.

Then yesterday I hear that Google (they don't need the miniscule PageRank boost I can offer on a link) has released an upgrade to their feed reader service. The interface is pretty slick. It lets me delete the 2000 odd feeds I had accidentally imported into the old interface in under 10 tries (the previous interface would have required me to delete each one; the new one just kept failing in the middle of each delete all). It's about as nice as the way I read my mail. And then I find the important part: if I put subscriptions in folders, then I can select to read an entire folder. It then interleaves the posts by date. Yay! Planet behavior! This is on top of all the other odd benefits, such as practically infinite history for as long as anyone has subscribed to the same feed.

Today I try to load it. I can't seem to get past the loading animation. Since it's just an animated GIF I have no way to tell if it's making progress. I'm sad. I try another browser. No go. I'm sure they'll fix it later. Mmm, proprietary serviceware indeed.

(0 Comments ) (0 Trackbacks) aggregators freesoftware

August 2006

Bikesheds: Naming pygame-ctypes; Pronouncements Posted 2006.08.26 09:03 PDT

Sometimes there are just a few too many bikesheds out there just begging to be painted. While I've managed to not quite join the discussions themselves, I just had to share my viewpoint somewhere...

pygame vs ctypes

There have been a couple threads on what to name what may or may not become the new pygame. Most recently a cutesy name pistol was suggested. All because of some hopes to avoid confusion over the original pygame name.

I think the worry about confusion is a red herring, so long as things are properly namespaced. The ctypes implementation is split into two levels: a SDL wrapper, and a pygame compatibility layer. The first comes under the SDL namespace, with entries like SDL.image, SDL.mixer, etc. The pygame compatibility layer should just be another one of these: SDL.pygame.

Then existing code can switch from import pygame to from SDL import pygame if it wants to leverage this layer. No crazy names that nobody understands. No confusion over which is being used. We're done.

TurboGears vs Django

There's a lot of kerfuffle on various python blogs about what Guido van Rossum did or did not pronounce about either TurboGears or Django being the official BDFL choice, and so forth. I have yet to see a single link to text that came from Guido himself. Please stop mountainizing this rumor until there is an email or blog post or video from Guido that the rest of us can read or watch.

As for which I prefer? I'm completely a roll-my-own type, as I only do websites like this one.

(3 Comments ) (0 Trackbacks) bikeshed python

Cankiri 0.2 Posted 2006.08.06 09:01 PDT

I've just released Cankiri 0.2. It's not all that different from 0.1, as most of the changes are to improve the user experience by decreasing unnecessary clicks.

I've made the assumption that when you start Cankiri you want to record, so instead of waiting for you to click the icon, it will automatically bring up the save dialog. I've also added fallbacks so that if you don't have a place for the notification area icon, it will create a little window for just its icon. This isn't pretty, but it ensures that if you can start a recording you can also stop it. The actual recording is then the same. If it worked for you in 0.1, it should still work; if it didn't work, I doubt it will suddenly start working. Let me know if any of these assumptions are a problem for you. I think next release I'll add command line arguments so defaults can be changed; if so I'll probably allow deferring the save dialog.

I have not been able to address a problem in the area selector. Both my friend Pete, and bloodsk are unable to resize it. Pete uses KDE with xinerama on FreeBSD where not only can he not resize the area selector, it shades the part inside. But when he tried Metacity without xinerama it was still immobile. Bloodsk reports being on Ubuntu Dapper, and hopefully will follow up here with what window manager or unusual X settings he might be using.

(0 Comments ) (0 Trackbacks) cankiri

July 2006

Cankiri 0.1 Posted 2006.07.29 23:21 PDT

As if I didn't have enough other projects on my hands, I've just put enough finishing touches on Cankiri to release it into the wild licensed under the GPLv2. It came about after looking at Istanbul around version 1.2 and being disgusted with the limited features and overengineering in the code. Come on, you don't need two directories and at least five files for this functionality. Really. Since then both Istanbul and I have added screen area selectors and audio recording. I've got all my code in one 400 line file; Istanbul now spans many more files. Where this really shows: ls -l.

It's amazing how concise you can be with python once you know what you're doing. I hope you find Cankiri easy to use, as a single-file distribution leaves no room for documentation. Let me know what you think.

(All the jabs at Istanbul's code aside, I'm very grateful for the GStreamer plumbing I've been able to take and reapply. Since I've yet to really learn GStreamer, this has been critical for me.)

(15 Comments ) (2 Trackbacks) cankiri gstreamer python

Previous entries