Python Programming, news on the Voidspace Python Projects and all things techie.

Kamil, Andrzej, PyCon UK, Python 3 and SSL

emoticon:pen_book Our intern Kamil Dworakowski has just started a blog:

He is a .NET expert and has been involved in the development of Nemerle, a functional programming language for .NET. His Python is coming along nicely as well. Wink

His first entry is about a re-entrance problem with the Windows Forms message box. The example code is (unsurprisingly) in Nemerle, which is pretty readable all things considered.

There is some depressing news from Resolver though. My friend and colleague, Andrzej, is leaving us to return to Poland. He will continue to work with us for one week a month, and there is a strong possibility that he will return in the new year, but it is still sad. Sad

We gave him a sendoff last night, and a special gift:

Polish Remover in Action with Andrzej

It seems to have done the trick! (Photo by Konrad who also has a cool blog.)

I guess that by now (due to the umpteen blog entries on Planet Python) you have heard that Python 3 alpha 1 has been released! Exciting stuff. What you might not have paid much attention to on the release page is the innocent sounding:

'SSL support is disabled. This causes test_ssl to be skipped. The new SSL support in the 2.6 trunk (with server-side support and certificate verification) will be ported for 3.0a2.'

If you follow Python-Dev, you will know that Bill Janssen has done a lot of working on adding some exciting new SSL features that will be available in Python 2.6 (and Python 3). This is also great news.

In the last part of this mish-mash of a blog entry, PyCon UK is nearly upon us. There are already 170 delegates signed up, which is cool because it means we beat PyCon Italia! We're really looking forward to PyCon at Resolver. Three of us are talking (and I've finished my Silverlight research - just the talk to write. I haven't spilled all the beans on the blog - there's more!). We may also be doing some subtle recruiting, so watch out. Wink

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-31 23:11:09 | |

Categories: , , ,


ExtJS Grid as Spreadsheet

emoticon:globesearch As I mentioned back in July, I've been experimenting with using the EditorGrid provided by the ExtJS Javascript Library as a 'spreadsheet in the browser'.

This is slightly different from the normal behaviour of the grid, because sometimes the grid needs to show a different value from the value that is edited. i.e. it needs to show the result of formulae, but when you go into edit mode by double clicking a cell, you need to edit the formula rather than the displayed value.

The application is a Silverlight app, with the spreadsheet engine written in IronPython. This means that I treat the Javascript grid as the 'view' and keep my own data model in Python. The data store associated with the grid only needs to keep the displayed values, but I need to swap out the displayed value with the edited value when entering edit mode - plus push the edited value back into the model when the edit is complete.

For this I've used some trickery, which I'm documenting here. Yes they're hacks, so if you know of a better way then feel free to let me know.

The grid has several useful events.

  • beforeedit - going into edit mode
  • validateedit - leaving edit mode
  • afteredit - left edit mode

During beforeedit we need to fetch the 'edited value' from the model. This can be set in the record exposed by the event.

function beforeedit(e) {
    currentcell.col = e.column;
    currentcell.row = e.row;
    currentcell.val = e.value;
    currentcell.finished = false;
    e.record.set(columns[e.column], getEditValue(e.column, e.row));
}
grid.on('beforeedit', beforeedit);

We also store the column, row and displayed value of the cell about to be edited on an object called currentcell. The reason for this will become clear shortly. I've also shown the call to set the event handler. Nice and simple.

Note

You need to pay attention to scoping (of course) if you are doing this for real. The example code here assumes that everything is in the same scope.

Additionally, the calls to the model are really calls into IronPython code in Silverlight. The whole spreadsheet engine (model classes and controller code) now occupies about 400 lines of Python.

When we get the afteredit event, the spreadsheet is recalculated. This potentially affects several cells, not just the one being edited (if you have a formula referencing this cell then the value of that will have changed as well). The call to setModelValue changes values in the grid's datastore by calling setcell.

function afteredit(e) {
    setModelValue(e.column, e.row, e.value);
    reload();
}

function setcell(s, col, row, value) {
    store.proxy.data[row][col] = value;
}

These changes will only be displayed in the grid if we reload the data. Unfortunately, reloading the grid loses the current selection which feels weird. reload fetches the selected location from the selectionModel (fetched with a call to grid.getSelectionModel()), tells the datastore to reload, and then restores the selection.

function reload() {
    // Reloads the displayed grid from the data store
    selectedLocation = selectionModel.getSelectedCell();
    store.reload();
    if (selectedLocation != null){
        selectionModel.select(selectedLocation[0], selectedLocation[1]);
    }
}

This all works very well, but it would be nice to be able to refresh only the cells that have changed rather than calling store.reload() which is expensive for large grids.

There is a serious flaw with this approach however. If you go into edit mode and then leave without making a change, neither validateedit or afteredit are fired. This leaves the edited value in the cell rather than the displayed value.

What we do get, if we look for it, is a lost focus (actually hide) on the TextField that ExtJS uses for inline editing of grid cells. My (current...) solution, is to set a timeout on the lost focus event that will reset the displayed value in the cell. If we get a validateedit event, then it simply clears the timeout and a recalculation is triggered as normal. A timeout of 10milliseconds seems to work very reliably, so there is no visible delay (and it usually wouldn't matter if both happened anyway).

We have access to the hide event when we create the column model for the grid:

function onHide(e) {
    // Call resetCell if the textbox disappears but no validate event occurs
    currentcell.timeout = setTimeout(resetCell, 10);
}
// shorthand alias
var fm = Ext.form;

// the column model has information about grid columns
cols = Array(columns.length);

// The row index is not editable
cols[0] = {
   header: '',
   width: 100,
   dataIndex: ''
};

for (index = 1; index < columns.length; index++) {
    col = columns[index];

    editor = new Ext.grid.GridEditor(new fm.TextField({ allowBlank: true }));
    editor.on('hide', onHide);
    cols[index] = {
       header: col,
       dataIndex: col,
       width: 100,
       editor: editor,
       sortable: false
    };
}

cm = new Ext.grid.ColumnModel(cols);

When the hide event fires the onHide function, it sets a timeout which will call resetCell. This uses the currentCell object prepared by beforeedit. If validateedit fires first, then it clears the timeout.

currentcell = {col: 0, row: 0, val: '', finished: false}
function resetCell() {
    // Reset the displayed value in a cell that is edited
    // but no changes are made.
    if (!currentcell.finished){
        store.proxy.data[currentcell.row][currentcell.col] = currentcell.val;
        reload();
    }
}

function validateedit(e) {
    clearTimeout(currentcell.timeout);
    currentcell.finished = true;
}

Suggestions for improvements welcomed! There is now an experimental datatable in the Yahoo User Interface Javascript Library (YUI). It looks very nice, but supposedly 'inline' cell editing is done with an ugly dialog style text box that I don't like.

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-28 23:24:11 | |

Categories: ,


New Geek 'Non-Gadget Gadget'

emoticon:eyeballz I have a new geek gadget, which isn't really a gadget at all (perhaps a meta-gadget?). It's a Scottevest Tactical Jacket (version 4.0 apparently [1]).

My wife is delighted; it's only the second time in four years of marriage that she has got me to buy clothing.

The jacket is a total luxury, but I had some gift cash and have wanted it for ages. It is billed as the ultimate geek jacket, which I think is fair enough. Waterproof and breathable (of course), with a plethora of pockets. (I love deep pockets - trousers with deep pockets is one of the best things about being a bloke.) The inside pockets are deep enough to hold magazines and the main outside pockets are also huge. Several of the pockets have magnetic catches which is a genius idea.

Scottevest are very proud of their 'patented' PAN system. This is the 'Personal Area Network', which in fact is just a series of 'tubes' for cables running through the jacket - which I probably won't use. They also claim that the jacket has 'weight balancing webbing', so that I won't be walking wonky even with all my gadgets on one side. I haven't yet tested this... Smile

The nasty sting in the tail (tale?) was the £60 import duty on top of the $300 for the jacket and shipping. ouch (12% import duty on clothes plus 17.5% VAT, plus an £11 charge by UPS to take it through the customs process. Because Scottevest lumped the cost of shipping into the item value, and listed shipping cost as zero, I got charged duty and VAT on an extra £30 'guesstimated' shipping cost by customs.) It only took four days to arrive from the US though, which was astonishing.

[1]Do you prefer parentheses to footnotes Nicola?

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-28 23:22:38 | |

Categories:


New Programs: Popfile and Better Gmail

emoticon:Lithium I've just discovered two new programs that are already invaluable, so I thought I'd share. Smile

Popfile is a bayesian spam filter that acts a POP proxy server. It is easy to setup and as well as classifying mail as spam it can classify incoming mail into as many categories ('buckets') as you like. The reason for using it is that Thunderbird's spam filter is crap - it lets about 10% of my spam through, and when I get several hundred a day that is way too much. After only three days (and 484 emails), popfile is already better than Thunderbird. The popfile docs say that it needs about 1000 emails to reach maximum efficiency. The Gmail spam filter is excellent, but the client is not as responsive as Thunderbird and lacks many of the features - so there is no need to suggest it.

However... what I do use Gmail for, is as an email 'archive'. The search is much better than Thunderbird's and I keep a copy of everything in gmail. Better Gmail is a Firefox extension (actually a set of compiled Greasemonkey scripts as a single Firefox extension). It integrates Google Reader into the Gmail interface, so I only need one tab open for both, and the 'Super Clean' skin is very nice. It does a few other useful things, like forcing an https connection even if you forget, so well worth installing.

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-28 19:26:44 | |

Categories: ,


T-Mobile, Web'n'Commute and Lost Productivity

emoticon:apple I have a(nother) new gadget, a Huawei 3G USB Modem. The vital added fact is that it came free with a T-Mobile Web'n'Walk subscription which will set me back the best part of thirty quid a month.

In one fell swoop this has destroyed my commute as a time of productivity, as I now have access to the internet. sigh Smile

The terms and conditions aren't too restrictive: I can use up to 3gig a month, which is fine for the email and browsing I do whilst on the train. It is a 3G modem, but will fall back to GPRS if 3G isn't available (suck on that iPhone!).

Setting it up was annoying though. I use it with my Mac laptop and at first it just plain refused to do anything. The worst part was that when I let Windows (through Parallels) control the device it worked fine, so I knew it wasn't a hardware or SIM problem.

However, I was astonished when I rang T-Mobile support. First off it was an '0800' number, which are free from landlines but cost a fortune from mobile phones. When the guy at the other end heard I was having problems with a Mac, the first thing he did was offer to phone me back after he went a got a Mac so he could take me through it. Sure enough he phoned me back in a few minutes and walked me through setting up the device.

It turns out that in the included Mac instructions they miss out a vital step. When logging onto the service you need to enter the username user and the password password. This is done for you from the Windows client which also has a nice traffic monitor which is missing with the Mac. Still, it works fine now. It's a shame that finding someone from a cellphone company who is knowledgeable, friendly and helpful is a shock - but that's the way it is. It would have been better if all the information had come with the device, but I can't fault their customer service. As I explain in my article From Problem to Profit, helping customers through difficulties is actually a great opportunity to win loyal customers.

At home and work I access my email via POP. I don't like the latency of IMAP as it makes the client unresponsive. Thunderbird with POP is much more responsive (and has more features) than Gmail, before you suggest that. Wink

My mobile connection is pretty good. It drops out about every fifteen minutes or so, which isn't bad for a train journey replete with tunnels and hills. I use IMAP because I don't want to download all my emails onto my laptop and then not be able to access them from work. (I still want to be able to delete them though, so POP that leaves them on the server is out.) Thunderbird and IMAP, with a slightly unstable connection, is very annoying. It won't let you save drafts if it doesn't have access to the drafts folder on the server, you delete things and then move focus to another email - and then it jumps your focus back after it has done the delete. Horrible user interface choices. Oh well.

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-28 19:25:42 | |

Categories: , ,


Windows User Rights

emoticon:halt I'm sure there is a lot to say on this subject, but this is just a brief entry about a particular situation I've been in.

I work one day a week at the Northampton Jesus Centre, a charity run by my church. I use a shared computer, logged onto the network as a 'normal user' rather than the power user or administrator that is more common for Windows. This causes all sorts of annoyances, like not being able to install stuff or Firefox continually attempting to update itself and failing - every time I use it.

Fortunately I know the administrator password, but switching users all the time is a nuisance.

I've just discovered the joys of the runas command. This means that I can run individual applications with elevated rights:

runas /noprofile /user:administrator firefox.exe

This prompts for the admin password before running, and runs Firefox with admin rights. Of course this is the worst of both worlds - running as a user with limited rights, but my browser running as admin! Surprised

I've stopped doing it, but it is still useful for doing updates without switching user. In fact this is not a bad situation: running under Windows as a restricted user but elevating rights temporarily for individual applications. My colleague Jonathan does this, and despite initial annoyances he now has it down to a fine art.

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-28 19:25:12 | |

Categories:


Playing Video with Silverlight

emoticon:envelope Although Silverlight comes with few controls, it does come with a fully functioning video player. This entry shows how to use the MediaElement from IronPython.

I've uploaded an example video (stolen from the Silverlight Mix UK Sample Site) so that this code can be tried from the Silverlight IronPython Web IDE.

The Web IDE doesn't normally use the Silverlight canvas, so to make the video visible we have to do two things:

  • Set the height and width on the plugin by setting CSS attributes. (The calls to plugin.SetStyleAttribute('height', '400').)
  • We need to add the newly created MediaElement to the canvas (by adding it to the Children collection). This is named 'root' in the XAML, and we have access to that name in our namespace from Python code.
Showing Video in Silverlight with IronPython
from System.Windows.Controls import MediaElement
from System import TimeSpan, Uri, UriKind
from System.Windows.Browser import HtmlPage

plugin = HtmlPage.Document.SilverlightPlugin
plugin.SetStyleAttribute('height', '400')
plugin.SetStyleAttribute('width', '400')

m = MediaElement()
root.Children.Clear()
root.Children.Add(m)

u = Uri('HelloWorld.wmv', UriKind.Relative)
t = TimeSpan(0)
m.Source = u
m.Position = t

playing = True

def OnClick(s, e):
    global playing
    if not playing:
        m.Play()
    else:
        m.Pause()

    playing = not playing
    if m.Position.TotalSeconds > 12:
        m.Position = TimeSpan(0)
        m.Play()
        playing = True

    print m.Position.TotalSeconds

m.MouseLeftButtonUp += OnClick

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-26 23:23:39 | |

Categories: , ,


Fetching Embedded Resources from IronPython

emoticon:acrobat The other side of the coin to my previous entry, is fetching resources embedded in an assembly from IronPython. Again, this is suitable for use from IronPython, where you may have text, images or video files embedded in an assembly.

import clr
from System.IO import StreamReader

assemblyName = 'EmbeddedIronPython, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
filename = "EmbeddedIronPython.SomeText.txt"

assembly = clr.LoadAssemblyByName(assemblyName)
stream = assembly.GetManifestResourceStream(filename)

reader = StreamReader(stream)
text = reader.ReadToEnd()

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-26 21:10:59 | |

Categories: , ,


Embedding IronPython in a Silverlight Assembly

emoticon:key Just as IronPython can be embedded in a C# application, it can also be embedded in a Silverlight application.

One interesting use case would be to use IronPython to provide a user scripting API for a Silverlight application.

The following code example shows how to use the IronPython API to execute a Python script that has been stored as an embedded resource (text file) in an assembly:

You will need to add a reference to the Microsoft.Scripting assembly, along with a using IronPython.Hosting; directive.

PythonEngine pe = PythonEngine.CurrentEngine;
string filename = "EmbeddedIronPython.PythonFile.txt";
System.IO.Stream stream = this.GetType().Assembly.GetManifestResourceStream(filename);
StreamReader reader = new StreamReader(stream);
string python = reader.ReadToEnd();
pe.Execute(python);

There is no need for the Python file to be an embedded resource of course. It can be stored as a separate file and fetched with a Downloader.

Note

This doesn't actually work from Silverlight because of a bug in the assumptions the DLR makes. You can see the whole solution at Embedding Silverlight in C#.

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-08-26 21:10:31 | |

Categories: , , ,


Hosted by Webfaction

Counter...