blog/ notes/ projects/ colophon

And it's all because of Django & Unicode

So I have this error in my Django page when trying to get some values via a many-to-many relathionship:

filter() keywords must be strings

in

/[...]/VIRTUAL_ENV/lib/python2.6/site-packages/django/db/models/fields/related.py in get_query_set line 497


  def get_query_set(self):
    db = self._db or router.db_for_read(self.instance.__class__, 
                                        instance=self.instance)
    return superclass.get_query_set(self)
                        .using(db)
                        ._next_is_sticky()
                        .filter(**(self.core_filters)) #<< Here

Which took me while to figure as being a Unicode handling problem between Django and Python (2.6).

Here are the initial conditions:

  • Snow Leopard shipped with python 2.6.1.
  • I use homebrew for installing extra software
  • The web app I am working on depends on (amongst many other):
    • Django 1.3
    • Cairo

Some other facts I have to work with:

  1. Django 1.3.1 does not fix the problem.
  2. Django 1.4 is still pre-alpha.
  3. We use a library which has issues with python 2.7 so it's out.
  4. The official python 2.6.6 OSX binary is i386 only.
  5. There is no homebrew package for python2.6.* anymore.
  6. There is no pip package for Cairo (py2cairo).

Django 1.3.1: no luck

So I tried to use Django 1.3.1 but it does not include the fix for this particular problem.

Django 1.4 pre-alpha : it says it all on the tin

No more luck with a checkout of Django 1.4 sources. Is still too much on the bleeding part of the bleeding edge (renamed packages, disappearing classes ... )

As newer versions of Django don't fix the problem let's try newer versions of python.

Python 2.6.6: too much pain

I installed Python 2.6.6 from the official OSX binary distribution. I Set up a virtual environement, but there were some problem with compiling libraries and re-using previously compiled library. It mostly revolved around architecture mismatch between i386 and x86_64:

Error was: 

dlopen([...]/ENV_py266/lib/python2.6/site-packages/cairo/_cairo.so,2): 
       no suitable image found.  
Did find:
       [...]ENV_py266/lib/python2.6/site-packages/cairo/_cairo.so: 
       mach-o, but wrong architecture

I would have to recompile pycairo with a different architecture and possibly other libraries. So I decided to skip it and got to the next option.

Python 2.6.7:

So I then had to try and install a newer version of python, from source. I might as well get the last: Python 2.6.7. Googling around I found an article about recovering the old Homebrew formula for python from github when the tracked python was 2.6.

The formula/repository seems to have moved from when the article was written (curl just gets a 301 when fetching the article's URL), so I went to the page to copy the final url from my browser. I modified the python source url and md5 to match that of the 2.6.7 version. I renamed the Formula and class to python2.6.7 and Python2.6.7 respectively before moving them to their destination. Building and installing was as easy as:

brew install python2.6.7 --universal
sudo brew link python2.6.7

I then created a new virtualenv using that new python. I copied my python 2.6.1 site-packages from my previous virtualenv over as well as the django project itself. To cleanup afterwards I ran the command bellow in the virtual env's root.

find . -name '*.pyc' -exec rm '{}' ';'

Finally I could start the django project !

Alas, as soon as I tried to get a page I got

Fatal Python error: Interpreter not initialized (version mismatch?)`

I narrowed it down to using a py2cairo compiled for the wrong python.

otool -L _cairo.so
...
=> /System/Library/Frameworks/Python.framework/Versions/2.6/Python (compatibility version 2.6.0, current version 2.6.1)
...

To compile py2cairo with the new python, this stackoverflow question about installing py2cairo on mac os x helped me get started but a bit more research into waf and actually reading the ld man was needed until everything could work together.

After downloading the [py2cairo library source][py2cairo] from its homepage I evolved the following script:

########################
# my messy part: Created by adding and tweaking until it works. 
# Some of it might be unncesary.

python waf clean

export PATH=/usr/local/Cellar/python2.6.7/2.6.7/bin:$PATH
export PYTHONPATH=/usr/local/Cellar/python2.6.7/2.6.7
export LD_LIBRARY_PATH=/usr/local/Cellar/python2.6.7/2.6.7:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/Cellar/python2.6.7/2.6.7/lib:$LD_LIBRARY_PATH
export LINKFLAGS='-search_dylibs_first  -L /usr/local/Cellar/python2.6.7/2.6.7/lib/'

# from stackoverflow 
# http://stackoverflow.com/
# questions/6886578/how-to-install-pycairo-1-10-on-mac-osx-with-default-python

export ARCHFLAGS='-arch x86_64'
export CC=/usr/bin/gcc
export PKG_CONFIG_PATH=/usr/local/Cellar/cairo/1.10.2/lib/pkgconfig/

python waf configure
python waf build

#To check against which python the lib was linked
otool -L build_directory/src/_cairo.so
########################

(gist on gihtub)

Once that worked, the output became:

otool -L build_directory/src/_cairo.so
...
=> /usr/local/Cellar/python2.6.7/2.6.7/lib/libpython2.6.dylib (compatibility version 2.6.0, current version 2.6.0)
...

I installed it in the virtal environment:

cp build_directory/src/_cairo.so $PY267/lib/python2.6/cairo/
echo "from _cairo import *" >> $PY267/lib/python2.6/cairo/__init__.py

And then the Django site finally worked :-)

Yay! Finally, my iPhone app is available on the app store! It took a while to create, it is a bit barebone, but it works and it is "available on the app store"! Its homepage is at www.displayator.com. There is also the help included in the app. It's only the begining, but at least there is finally a visible step :-D.

This is the internet from Dili, on the Timor Telecom Netbo'ot Xlais (3G) plan. The one that takes you 1 month and a letter from one's wife's employer to get. One month because the billing system for post-paid plans is down from the last upgrade. And a letter from a UN organization or Big Company because there is no such thing as automatic bank transfer (yet) in East Timor or much of a postal service. So they need a stable organization to vouch for you. And you have to go to their office to pay the internet bill. In cash.

So here are a few ping times for github.com.

When it's not working so good:


PING www.github.com (207.97.227.243): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
Request timeout for icmp_seq 4
Request timeout for icmp_seq 5
Request timeout for icmp_seq 6
Request timeout for icmp_seq 7
Request timeout for icmp_seq 8
Request timeout for icmp_seq 9
Request timeout for icmp_seq 10
Request timeout for icmp_seq 11
Request timeout for icmp_seq 12
Request timeout for icmp_seq 13
Request timeout for icmp_seq 14
Request timeout for icmp_seq 15
Request timeout for icmp_seq 16
Request timeout for icmp_seq 17
Request timeout for icmp_seq 18
Request timeout for icmp_seq 19
64 bytes from 207.97.227.243: icmp_seq=0 ttl=48 time=21000.422 ms
64 bytes from 207.97.227.243: icmp_seq=1 ttl=48 time=20497.055 ms
64 bytes from 207.97.227.243: icmp_seq=2 ttl=48 time=20422.630 ms
64 bytes from 207.97.227.243: icmp_seq=4 ttl=48 time=18556.737 ms
64 bytes from 207.97.227.243: icmp_seq=5 ttl=48 time=17873.283 ms
64 bytes from 207.97.227.243: icmp_seq=7 ttl=48 time=16648.719 ms
64 bytes from 207.97.227.243: icmp_seq=8 ttl=48 time=15675.208 ms
64 bytes from 207.97.227.243: icmp_seq=11 ttl=48 time=16667.384 ms
64 bytes from 207.97.227.243: icmp_seq=12 ttl=48 time=15810.244 ms
64 bytes from 207.97.227.243: icmp_seq=13 ttl=48 time=15127.921 ms
...

Still works, kinda.

Here it is at its best:

PING www.github.com (207.97.227.243): 56 data bytes
64 bytes from 207.97.227.243: icmp_seq=0 ttl=46 time=750.208 ms
64 bytes from 207.97.227.243: icmp_seq=1 ttl=46 time=749.479 ms
64 bytes from 207.97.227.243: icmp_seq=2 ttl=46 time=748.548 ms
64 bytes from 207.97.227.243: icmp_seq=3 ttl=46 time=758.857 ms
64 bytes from 207.97.227.243: icmp_seq=4 ttl=46 time=758.581 ms
64 bytes from 207.97.227.243: icmp_seq=5 ttl=46 time=747.524 ms
64 bytes from 207.97.227.243: icmp_seq=6 ttl=46 time=767.582 ms
64 bytes from 207.97.227.243: icmp_seq=7 ttl=46 time=811.335 ms
64 bytes from 207.97.227.243: icmp_seq=8 ttl=46 time=746.080 ms
64 bytes from 207.97.227.243: icmp_seq=9 ttl=46 time=747.759 ms
64 bytes from 207.97.227.243: icmp_seq=10 ttl=46 time=747.045 ms
64 bytes from 207.97.227.243: icmp_seq=11 ttl=46 time=786.805 ms
64 bytes from 207.97.227.243: icmp_seq=12 ttl=46 time=754.027 ms
64 bytes from 207.97.227.243: icmp_seq=13 ttl=46 time=803.607 ms
64 bytes from 207.97.227.243: icmp_seq=14 ttl=46 time=775.936 ms
^C
--- www.github.com ping statistics ---
16 packets transmitted, 15 packets received, 6.2% packet loss
round-trip min/avg/max/stddev = 746.080/763.558/811.335/20.689 ms

Oh well.

Timor telecom is a joint venture with Portugal Telecom. East Timor is not connected to any subsea cable, so the access to the rest of the workd is by satellite. Until recently, the downlink was in Portugal, but I noticed today that it is now in Los Angeles, apparently even for european traffic :


Ikki-8:~ niko$ traceroute www.lemonde.fr
traceroute to orig-10011.lemonde.cotcdn.net (208.93.141.60), 64 hops max, 52 byte packets
 1  10.68.1.10 (10.68.1.10)  58.393 ms  48.982 ms  49.887 ms
 2  202.72.107.233 (202.72.107.233)  49.991 ms  48.808 ms  60.100 ms
 3  isp_rtr_ewsd.timortelecom.tp (202.72.104.25)  289.717 ms  198.158 ms  312.755 ms
 4  97.208.119.74.in-addr.arpa (74.119.208.97)  614.660 ms  714.006 ms  730.549 ms
 5  2.255.113.74.in-addr.arpa (74.113.255.2)  663.001 ms  709.718 ms  717.103 ms
 6  218.255.113.74.in-addr.arpa (74.113.255.218)  716.161 ms  715.386 ms  817.722 ms
 7  166.255.113.74.in-addr.arpa (74.113.255.166)  629.226 ms  700.693 ms  819.343 ms
 8  ae5-286.edge6.losangeles1.level3.net (4.59.50.49)  716.484 ms  920.396 ms  715.551 ms
 9  ae-3-80.edge2.losangeles9.level3.net (4.69.144.143)  736.165 ms
    ae-1-60.edge2.losangeles9.level3.net (4.69.144.15)  717.403 ms  718.268 ms
10  4.53.230.26 (4.53.230.26)  713.741 ms  716.148 ms  619.068 ms
11  lb140.lsag.cotendo.net (208.93.141.60)  814.379 ms  705.175 ms  716.141 ms

Another french site :


traceroute to www.macbidouille.fr (212.43.222.205), 64 hops max, 52 byte packets
 1  10.68.1.10 (10.68.1.10)  53.321 ms  58.998 ms  59.884 ms
 2  202.72.107.233 (202.72.107.233)  58.490 ms  54.145 ms  60.118 ms
 3  isp_rtr_ewsd.timortelecom.tp (202.72.104.25)  229.907 ms  247.107 ms  385.811 ms
 4  97.208.119.74.in-addr.arpa (74.119.208.97)  574.238 ms  580.288 ms  568.438 ms
 5  2.255.113.74.in-addr.arpa (74.113.255.2)  630.950 ms  627.160 ms  639.982 ms
 6  218.255.113.74.in-addr.arpa (74.113.255.218)  639.453 ms  638.748 ms  749.713 ms
 7  166.255.113.74.in-addr.arpa (74.113.255.166)  661.317 ms  767.899 ms  628.394 ms
 8  ae5-286.edge6.losangeles1.level3.net (4.59.50.49)  731.870 ms  664.324 ms  716.819 ms
 9  ae-44-90.car4.losangeles1.level3.net (4.69.144.198)  679.359 ms
    ae-24-70.car4.losangeles1.level3.net (4.69.144.70)  731.518 ms
    ae-14-60.car4.losangeles1.level3.net (4.69.144.6)  715.088 ms
10  globalcrossing-level3-10ge.losangeles1.level3.net (4.68.110.66)  716.510 ms  770.715 ms  750.373 ms
11  204.245.38.142 (204.245.38.142)  819.176 ms  716.645 ms  818.951 ms
12  th2-cr1-ge-2-4.router.fr.clara.net (212.43.193.209)  819.045 ms  741.612 ms  829.885 ms
13  fb-cr2-ge-0-2.router.fr.clara.net (212.43.193.181)  820.216 ms  818.374 ms  820.142 ms
14  fb-fb-ar1-ge-7-2.router.fr.clara.net (212.43.193.222)  708.126 ms  716.031 ms  734.438 ms
15  16.216.rev.dc-zone.net (212.43.216.16)  802.604 ms  818.576 ms  727.429 ms
16  * * *
17  * * *
18  * * *
19  * * *
20  * * *
...

Still shorter than talking to the moon I guess :-).

After almost a year of not flying easyjet (yay flybaboo!), I had to go to Bordeaux, and the only convenient times were offered by Air France (via Paris : min : 3 h 30) or easyjet. And Easyjet was half the price and a third the time of Air France.

After dodging the speedy boarding, travel insurance, 'extra' luggage, hotel booking, car rental, remembering my password, narrowly avoiding the credit card extra charges (backtrack to step 2, change currency to euro, do the above again then change payment method to 'carte bleu'), I am greeted by this:

wtf Easyjet

Which, according to google translate is the Croation blurb about not leaving your luggage unatended etc...

The page was all in french, the ads were all in french except this paragraph. WTF ?!?

On the 42nd day of a streak in calendar about nothing I simply forgot to do and commit something. After a new streak was well underway, I decided to add a snapshot of the page to my Mac desktop, so as to try and ward off another lapse. A quick google search found CutyCapt, a Qt & Webkit based program available as a Windows binary or as source code. As I already had installed Qt, Xcode and GeekTool, I decided to use the source code rather than look for something simpler to install.

GeekTool is a very practical app for Mac OS that allows you to display images, text files or shell scripts result in a layer between your desktop image and your desktop icons.

Here is what the combination of the above can look like :

Geektool + calendar about nothing - All the crap usually lying around on the desktop have been moved to the 'all my stuff' folder for this posed screenshot.

If you are not interested in installing Qt, Xcode and compiling random source files, you can download CutyCapt in binary form for mac and skip to the GeekTool setup. Or you can build it from source. For that option, you need to use the Terminal, and already have Xcode and Qt installed.

How to build CutyCapt (once you have all the prerequisites installed):

  • Download and untar the CutyCapt sources from the website (scroll down).
  • In the Terminal, cd to the directory extracted from the archive and run qmake (no option), which will generate the Xcode artefacts.
  • Compile the Mac binary by running xcodebuild (no option either). The binary will be in the newly created CutyCapt.app/Contents/MacOS/* directory. You can copy it to some shorter path if you want.

Setting the image on the desktop :

The following setup will download your calendar page and wait 5 seconds for the scripts and css to execute, render the result, and repeat this every hour (the echo 'last updated the image on :';date; part it to see when the command was executed last).

  • Install GeekTool
  • In the GeekTool preference pane, drag a Shell widget to your desktop, for calling the CutyCapt.
  • In the Command field, put, all in one line, echo 'Last updated the calendar snapshot on :' ;date ;{path/to/CutyCapt/binary}/CutyCapt --url=http://calendaraboutnothing.com/~{your github account} --delay=5000 --out={somewhere/on/your/machine}/calendaraboutnothing.png.
  • Set the Refresh to 3600 seconds.
  • In the GeekTool preference pane, drag an Image widget to the desktop.
  • In its option, click "Set local path" and select the image generated by the script setup above (GeekTool will refresh the image when it notices that the image has been updated).
  • Done.

The image will be rendered every hour on you desktop. Once you're done for the day, you can de-activate this group in the GeekTool menubar menu.


blog/ notes/ projects/ colophon