Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Publicaciones sobre python (publicaciones antiguas, página 12)

A *real* programming challenge.

A long time ago, I wrote a piece about how I did­n't like kcal­c. It con­tained a very lame pyqt script show­ing a (IMHO) nicer cal­cu­la­tor. Strange­ly, that lead to two very cool im­ple­men­ta­tions of the con­cep­t!

One of them was writ­ten in Ruby, the oth­er one in C++. I think that has some po­ten­tial.

A few months lat­er, I wrote a spread­sheet based on the same con­cep­t. Al­so based on PyQt.

This Stupid­Sheet has some con­cep­tu­al prob­lem­s. Like, if you want to im­port Ex­cel sheet­s, you would have to re­write ba­sic in python, so it's not a prac­ti­cal pro­gram, but it is a rather nice ex­am­ple show­ing pro­gram­ming us­ing dy­nam­ic lan­guages.

In fac­t, I used it as such last week at Cafe­Con­f.

Now, here's the chal­lenge. If peo­ple that know how to write Ru­by or Ja­va apps us­ing Qt (or KDE, why not) could write a sim­i­lar ap­pli­ca­tion, we all could write a com­par­a­tive guide to Qt/KDE pro­gram­ming on dif­fer­ent lan­guages.

Since we would all be start­ing with a not-­too-­com­plex, but re­al­ly non-triv­ial ex­am­ple, and we would all do the same one, it should be pret­ty un­bi­ased.

In fac­t, if you think this ex­am­ple is bi­ased, please pro­pose an­oth­er one, and do this thing any­way.

You can find Stupid­Sheet here

It has some small bugs (try set­ting B1 to A1+1 with no val­ue in A1 ;-) but they are easy to fix.

We could re­move some fea­tures (like the weird past­ing stuff) to make the ex­am­ple more di­dac­tic.

I hope this gets some an­swers :-)

CafeConf 2005

Nue­va­mente este año voy a es­tar en Cafe­Conf . Es una char­la de 45 min­u­tos so­bre PyQt el 13 de oc­tubre al mediodía.

La idea: La gente se sor­prende cuan­do uno agar­ra KHTM­L, en­gan­cha un par de wid­gets y sale con un nave­g­ador we­b. Se de­be­ri­an sor­pren­der más de que uno puede par­tir de una re­c­eta de 20 líneas en una pági­na web y ter­mi­nar con una planil­la que fun­ciona ;-)

Por lo tan­to, voy a mostrar Stupid­Sheet co­mo un ejem­p­lo de que el de­sar­rol­lo de soft­ware con in­ter­face grá­fi­ca es mas facil de lo que la gente cree.

Co­mo siem­pre, si men­cionás es­ta pági­na, te ganás una cerveza. Máx­i­mo 2 cerveza­s, no muy bue­nas.

I will be at Cafe­Conf again this year. It's a 45-minute thing about PyQt in Oc­to­ber 13th, at noon.

My idea is: Peo­ple are amazed when you hook Khtml to a cou­ple of wid­gets and write a lame web brows­er. They should be more amazed that it is pos­si­ble to start with noth­ing more than a 20-­line recipe from a web­site and end with a func­tion­al spread­sheet ;-)

So, I will be show­ing Stupid­Sheet as an ex­am­ple of how writ­ing GUI soft­ware in Python is sim­pler than peo­ple think.

As usu­al, if you men­tion this page, you get a free beer, max­i­mum 2 beer­s, and not very good beer.

Authenticated Pages in CherryPy

Cher­ryPy is a cool, python­ic, sim­ple, quick, fun way to write web ap­pli­ca­tion­s.

I of­ten use Cher­ryPy to write cus­tom web ad­min tools for cus­tomer­s. Sup­pose you want to pro­vide them with a sim­ple way for pass­word man­age­men­t. Usu­al­ly I have the fol­low­ing re­quire­ments:

  • It must be sim­­ple ( not we­b­min )

  • It must not be a ter­mi­­nal ses­­sion (bye ssh :-( )

  • It must not be a graph­i­­cal ses­­sion (sad­­ly, that leaves out PyQt :-( )

  • It needs to do cus­­tom stuff: set the sam­­ba pass­­word at the same time, send a mail warn­ing about the next forced change, what­ev­er.

Some­day I may be able to use a sin­gle-app freeNX ses­sion, but right now that's a bit too much prob­lem for dif­fer­ent rea­son­s.

So, I wrote a Cher­ryPy page. Over time, I have be­come quite fond of it, and wrote a bunch of small tools around it. One of them was a way to lo­gin the us­er in­to the site us­ing the sys­tem's users and pass­word­s. Now I got to throw it away :-)

The new Cher­ryPy 2.1 has a mech­a­nism for im­ple­ment­ing pass­word-pro­tect­ed pages, called the Ses­sion au­then­ti­cate fil­ter which is sad­ly not doc­u­ment­ed yet any­where I can find.

So, here is my at­temp­t, so peo­ple googling it up can use it. Ex­cuse me:

cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter cher­rypy ses­sio­n­au­then­ti­cate­filter

That should do it :-)

What you need first is a func­tion that takes a user­name and pass­word, and re­turns None on suc­cess, or an er­ror mes­sage for the fail­ure.

For example, I can adapt something I wrote earlier using check­pass­word-­pam

def validPass(name,password):
                cmd='/usr/bin/checkpassword-pam -s xdm -- /bin/true 3<&0'
                print cmd,s
                if r==None: #Success
                        return None
        return "Login Incorrect"

Al­so, you may want a func­tion that re­turns the lo­gin screen. If you do, re­mem­ber the fol­low­ing:

  1. It must set the form ac­tion to doLo­gin

  2. The us­er field should be called lo­gin

  3. The pass­word field should be called pass­word

  4. You will take a fromPage ar­gu­ment that you should pass through, so the us­er will end on the page he wants.

  5. You will take a er­rorMsg ar­gu­ment which is prob­a­bly the re­sult of a failed pre­vi­ous lo­gin. Dis­play it red or some­thing like it. Un­less it's emp­ty, in which case it should not be vis­i­ble.

Here's mine.

def loginScreen(fromPage, login = '', errorMsg = ''):
<form method="post" action="doLogin">
<div align=center>
        <span class=errormsg>%s</span><p>
        <table >
                <input type="text" name="login" value="%s" size="40"/>
        <input type="password" name="password" size="40"/>
        <input type="hidden" name="fromPage" value="%s"/>
        <td colspan=2 align=right>
        <input type="submit" value="Login" />
""" % (errorMsg, login, fromPage)
return renderTemplate(file='logintemplate.html')

Al­though I am us­ing a tem­plate to dis­play it nice­ly and with the right style, it should be pret­ty ob­vi­ous how it work­s.

You could use the de­fault lo­gin screen pro­vid­ed by the fil­ter. While it work­s, it's just ug­ly.

Then you need to ap­ply the fil­ter to the set of your pass-pro­tect­ed pages. Sup­pose you want the whole site to be pro­tect­ed, ex­cept for your /stat­ic di­rec­to­ry, which con­tains the stylesheet, im­ages and such. Then you put this in your con­fig­u­ra­tion file:



Next thing is to hook the ses­sion au­then­ti­cate fil­ter to your cus­tom auth code. In your ap­p, do the fol­low­ing. It seems that you can't do this in the con­fig file, though, so do it in code.

            '/': {
                                    'sessionAuthenticateFilter.checkLoginAndPassword': validPass,

And that's it. Now your site is pass­word pro­tect­ed. You can even have dif­fer­ent au­then­ti­ca­tion schemes for dif­fer­ent pieces of the site, by re­set­ting the hooks for the fold­er you pre­fer to a dif­fer­ent func­tion.

Al­so, I think this is a good ex­am­ple of why I like Cher­ryPy. This mech­a­nism is both flex­i­ble, pow­er­ful and sim­ple.

Small Linux Revisited

A Lit­tle His­to­ry

Many moons (al­most two years!) ago, I wrote an ar­ti­cle called Small Lin­ux de­tail­ing what I had done to make a rea­son­able Lin­ux fit in a Toshi­ba Li­bret­to 50.

That's a very lim­it­ed note­book, with un­der 800MB of disk, a 75Mhz Pen­tium CPU and 16MB of RAM, and it has served me well for a long time.

Now, how­ev­er, I am us­ing the al­most ex­act op­po­site, a sec­ond-­hand Toshi­ba Satel­lite 1955-S805.

Where Salma (the Li­bret­to) had a 640x480 screen, Mon­ty (Toshiba), has a 16" 1280x1024. The RAM has in­creased 32 times. But they have one thing in com­mon....

The 800MB HD

You see, Mon­ty is sec­ond hand. My fu­ture moth­er-in-law and broth­er-in-law brought it from New York when they vis­it­ed, for Rosario (My fu­ture wife, un­til Feb­ru­ary 18 2006 ;-).

And it had a bro­ken HD. And I want­ed to use it while I got a nice new 60GB one.

So, over­com­ing my fear of de­stroy­ing ex­pen­sive equip­men­t, I got the HD out of Salma and in­to Mon­ty, and start­ed think­ing....

The Tallest Guy In The World

He had a prob­lem: re­al­ly bad feet. He died of it, too. In the same way, Mon­ty now boot­ed, but the app se­lec­tion was out­dat­ed, and re­al­ly, lots of things Salma could­n't do, Mon­ty could.

What on earth can one in­stall on that disk when you don't have any oth­er re­al hard­ware lim­i­ta­tion­s?

The choice of dis­tri­bu­tion was trick­y.

I am a Cen­tOS guy late­ly, but the pack­age se­lec­tion is en­tan­gled enough that you can hard­ly get X in­stalled with­out cross­ing the 800M­B. The min­i­mal in­stall is about 450M­B.

De­bian again? Well... no.


Now, that has some se­ri­ous po­ten­tial, since I could run the OS from DVD/CD, and then use the whole 800MB for da­ta. But I want­ed some­thing where I could choose what to in­stal­l.

I could have gone the path of one of the mod­u­lar Knop­pix deriva­tives, but it was yet an­oth­er task on the pile.

So, I went with­.... ARCH.

ARCH Is Arch

Yes, ARCH is saucy. It in­stalls in rough­ly 200M­B, in­clud­ing ker­nel sources and GC­C. That's quite smal­l.

I man­aged to cre­ate a rea­son­able desk­top in about 550M­B, in­clud­ing:


A nice text ed­i­tor


Need­ed it to work in a few prog­gies.


I have the RAM. The CPU is a 2.56 P4.

Xorg 8.2 with Nvidia drivers:

And just for kick­s, 3d­desk­top to see if they work ;-)


I know it, and it's nice enough.


Nicer than xter­m, and has a handy SSH builtin.

ROX Filer:

Not re­al­ly all that use­ful, but what the hel­l, for 3MB you get side­bars, a file man­ag­er and a few ex­tra trick­s.


A very nice xdm re­place­men­t. Spe­cial­ly with the mind­lock theme :-)


Com­press the ex­es. Save 30M­B. Good.


It's what I am work­ing with. And it's on­ly 74K­B.


Sim­ple, small tool to set the X root dec­o­ra­tion.


Stay synced with my old­er desk­top.

All in­clud­ed, I am at 120 pack­ages, us­ing 557MB of disk (with ex­ten­sive trim­ming, see the orig­i­nal ar­ti­cle for some ex­am­ples).

So, what's the dif­fer­ence be­tween this set of apps and my pre­vi­ous choice....

Well, look at the re­sult of free:

             total       used       free     shared    buffers     cached
Mem:        512544     408924     103620          0      33468     162916
-/+ buffers/cache:     212540     300004
Swap:            0          0          0

Just for laugh­s: here's the old one, when do­ing rough­ly the same things: edit­ing an ar­ti­cle, brows­ing the we­b, a few ter­mi­nal­s:

                total    used    free    shared   buffers        cached
Mem:            14708   14144     564      4644       816          5304
-/+ buffers/cache:       8024    6684
Swap:           47992   18880   29112

Scary is­n't it? I am us­ing rough­ly 25 times the amount of mem­o­ry I used on the li­bret­to. It's easy to see why, tho.

Con­sid­er the desk­top. It shows a pret­ty pic­ture. It is 1280x1024. It is in mil­lions of col­ors. That is in RAM. That is ei­ther 3932160 or 5242880 bytes. On the li­bret­to, I was in­ten­tion­al­ly not us­ing any­thing there :-)

So, it re­al­ly is not com­pa­ra­ble any­way, and Mon­ty's life as a mal­formed box will be short. But it was quite a bit of fun :-)

Not letting stuff fall off the ' net

For a bunch of apps I write, I of­ten want to be able to add a systray icon.

But... I write them us­ing PyQt, and the systray stuff is in PyKDE.

But... Torsten Marek did write a mod­ule to do that. The on­ly prob­lem for me is the python-c­types re­quire­men­t, but it's no big deal for my apps that are not mas­sive­ly de­ployed.

You can find his code, in a some­what man­gled for­m, here

And since build­ing ex­ten­sion mod­ules is not com­plete­ly triv­ial, here's a sim­ple set­ that will do it:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from distutils.core import setup
from distutils.extension import Extension

  name = "systray",
    Extension('traywin', ['traywin.c'],  libraries=["X11"],library_dirs=['/usr/X11R6/lib'])],

Put it in the same folder with his code, then you can do python install or somesuch, then you can use it in your app like in Torsten's example, and it will work.

Contents © 2000-2020 Roberto Alsina