Posts

Showing posts from November, 2006

Oracle from Python in Linux

Well, pretending to know everything can have its downsides. Like when the boss says "Could you hack up a script to enter custom data into our 3rd party invoicing software?". One choice is to admit that you would not know where to start. The other would be to attempt to muddle through. "Of course, let's have a look". So an hour later we have discovered that the software in question uses an Oracle back-end: Excellent, this is going to be easy, Oracle is an relational database (I read once somewhere) and we learned SQL at university, so it can't be that hard. So, step one: boot into windows, and use the command line client to do some stuff. Great! The SQL is coming back to me already. But this is no good. I can't use windows! The single desktop is beginning to upset me, and well we need it running on Linux so I can feel leeter than my coworkers. So what will we be needing? 1. SQLPLUS for Linux (this the the command line client for Oracle). Should be easy en...

Python Dates

At first glance the datetime module in the python standard library (full documentation available at http://docs.python.org/lib/module-datetime.html appears as an insane mish-mash of things. The types it makes available are date, time, datetime and timedelta. My initial confusion stemmed from the fact that the module name is the same as one of the type names (datetime and datetime.datetime) and this is one of the only times when I have thought that naming types in camel case is a good idea: datetime.DateTime might have been a saner approach. Nevertheless, we continue: A datetime.time is a time, a datetime.date is a date, and a datetime.datetime is a date with a time. A datetime.timedelta is a difference between any of these times. Simple enough. Usage of these types can be made easier by using their "alternative constructors" which are a set of class methods, and can in some cases be more useful than the actual constructor. For example: >>> from datetime import date...

Rat, more easy PyGTK dialogs

Image
We have been indulging in some Kiwi-love recently. You may have read the recent blog about easy PyGTK dialogs with Kiwi. After a chat with the author of another PyGTK helper library (called rat) and available at http://python-rat.berlios.de/ , who also happens to be a good friend of mine, I have decided to blog a similar example of dialogs using rat. Rat has a similar set of dialogs (a few extra, and a few missing). We shall start with a simple error dialog: >>> from rat.hig import error >>> error('You made a mess in your trousers', ... 'Or maybe the mess was already there', ... title='A big mess!') A similarly simple API, and it gives us a similarly HIG-compliant error dialog: Rat does not contain a yes/no dialog, but it does contain an ok/cancel dialog. Usage is again very quick and simple: >>> from rat.hig import ok_cancel >>> from gtk import RESPONSE_OK >>> r = ok_cancel('Are you s...

Kiwi, Pain free PyGTK dialogs

Image
Since we are in love with Kiwi, we will mention another amazing thing it has done for us. HIG Dialogs. HIG are the (Gnome) Human Interface Guidelines, a set of guidelines for creating accessible user interfaces. I wish we could ignore these things, but unfortunately we can't. You can read about them here . Kiwi has a set of dialogs ready for us that conform to these guidelines. They are presented in the form of funcitons that you can call, and which give you a response of some kind. Let's have a look: >>> from kiwi.ui.dialogs import error >>> error('You screwed something up', ... 'Or maybe it was already screwed to begin with') Yes, it is as simple as that. None of that boilerplate code. And the dialog itself actually looks quite nice: The error dialog is not the only one available of course. You have error, info, save, open, and my favourite: yesno >>> from kiwi.ui.dialogs import yesno >>> from gtk import RESPONSE_YES >...

Kiwi proxy widgets, a common widget API

Image
While we are on the notion of Kiwi , the PyGTK helper library, we should be discussing the proxy widgets. They offer a certain set of advantages over their plain PyGTK counterparts: They have a common signal emission API for change in content They offer a common API for setting and reading their value. They offer validation, and coercion They contain a few general improvements over the plain PyGTK widgets What does this mean? Simply it means you can make any data widget (eg Entry, CheckButton, Combo etc), you can connect its signal "content-changed", you can read the data with widget.read(), and set the value with widget.update(). If you have read any of the previous blogs about adapting Zope.schema fields to widgets, and you are alert, you will notice that this is amazingly useful. It means that we can define an interface for a general InputWidget type, something like: class IInputWidget(Interface): def read(): """Read the value in the widget"""...

PyGTK lists made easy with Kiwi

Image
Making nice lists is an utter pain with PyGTK. GTK+ does you the pleasure of separating the model and the view. I guess it is a reasonable idea in theory (don't they always teach you to separate the model and the view?) and allows you to have alternative views of the same model, and allows you to extend the implementation in any sort of way. BUT, to repeat: in most cases it is an utter pain. Even the simplest list becomes a mess of boilerplate code. Anyone who has done a decent amount of PyGTK programming will have written their own implementation of model+view mixed together, but the best one I have used is from Kiwi. If you have never used it, Kiwi is a framework that lessens some of the painful aspects of PyGTK development. In fact, it's so useful, let's call it a library. Creating a pythonic view of a list of objects is easy. Let's have a look at some code: from kiwi.ui.objectlist import ObjectList, Column class Fruit(object): def __init__(self, name, is_red): self...

Zope in a gui, fields as widgets

This is a long quest, and at this stage we have objects, which implement interfaces, and we have schemas that reflect the interfaces, and are helpers for creating views for the objects. This is all well and good, but what happens on a widget level in a gui? Well we can give you a simple example. The view is an adaption of the Schema, and which then has its content set (see the last blog about this topic) . The view can be built by adapting each of the schemas fields into a gui element, exactly as you would build a web form. Say you have an attribute defined as a zope.schema.Text, and you wanted an editor field. Well simply, using pygtk: import gtk from zope.interface import implements, Interface, Attribute from zope.component import adapts, provideAdapter from zope.schema import Text class IWidget(Interface): def write(value): """display the value""" class TextWidget(gtk.Entry): adapts(Text) implements(IWidget) def __init__(self, field): self._fie...

In search of a zope gui, why the zope web way might not be the best way

So in our last post, we saw how you could use the Zope interface architecture to adapt objects to views, and how Zope does it. The ultimate goal of this exercise is to have a gui way of representing Zope. This is all fine, but we have to consider that perhaps in a gui, one view per object may not be the best method. Creating a gui repeatedly for the same type of object, just to change its contents is just wrong. In our example, we had a multi-adapter for IObject, IRequest, which was a view object with a render method. No doubt perfect for web requests, but not for a gui which lives in a loop, is governed by events and can hide lots of stuff. What it seems we actually need is an adapter for ITypeOfObject, which is creaeted without an object, and can then have the content set and reset. Enter zope.schema zope.schemas are interfaces and have all the interface properties. They do have additional niceties, in that you can define attributes as constrained field types, for example Int, and in...

Using multi-adapters a la Zope

As a brief discussion (and I should mention that this has nothing to do with a web application), you have an object and you want to look at it. Imagine you have gone the whole way with this concept and you have arrived at Zope. Zope contains mechanisms for definition, storage and manipulation of objects, all using Python. So you have an interface: from zope.interface import Interface, Attribute class IFruit(Interface): name = Attribute("""The name of the fruit""") Ok, it's simple. Now you write a class that implements this, still simple. class Fruit(object): implements(IFruit) def __init__(self, name): self.name = name Pretty good. You can store that in an object database like ZODB if you like, but we are going to think how to view it. A view (in Zope terminology) is something that adapts (multi-adapts) a "context" and a "request". We don't really understand what a "context" is, so we are going to call ...