Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Saturday, March 10, 2012

deansi: ANSI colors to html in Python

Let me introduce you deansi, a python module to convert ansi terminal codes to html.

Lately, I am doing some refactorings, enhancements and fixes on TestFarm which lacked of care from us, regardless we use it for CLAM, for our daily work at Barcelona Media, and even to control the status of the unit tests of our students assignments. The testing framework we use for our tests, MiniCppUnit, relies on ANSI colors to highlight the important bits at the terminal output. Sadly, ANSI codes have the opposite effect when you look at that output from the Testfarm summary pages, it gets all quite screwed up.

I gave from granted that there were a common python library or recipe to convert ANSI color codes to html i could use. But i just found this recipe and, in fact, I modified Testfarm to use it, but it seems it is not that reliable and the code had to be extended to do quite basic things. So I decided to spike a test driven developed converter.

I made the module available at GitHub. Its features are:

  • Supports most 'm' codes (colors and attributes).
  • Fully stylable. It generates a default stylesheet but you can redefine the rules in many ways. For example you can make the colors be different in different containers within the same page (a case i need for TestFarm) or setting style properties for combination of active attributes.
  • It is test driven developed and back2back tested, so it is quite reliable, and in the long term features can be extended being quite sure we are not breaking existing functionality.
  • Unlike the recipe i found, it does not expect a given pair of starting and closing codes. It is implemented as an state machine, a new span tag is created at every attribute set change having as many html classes as attributes are active at that moment.
  • You can use it as module or as a command line tool although command line usage is quite minimal (pipe or single input file parameter)

How it works? If you use it as a python module, you can use it that way:

import deansi

html_template = """\
<style>
.ansi_terminal {{ background-color: #222; color: #cfc; }}
{defaultStyle}
</style>
<div class="ansi_terminal">{ansiText}</div>
"""
ansiInput = "\033[31mHello World!!\033[m"

print html_template.format(
defaultStyle = deansi.styleSheet(),
ansiText = deansi.deansi(ansiInput),
)
You can change the colors displayed adding style rules after the default ones, for example if you want to change the yellow color when the ansi bright attribute apply, and not to apply bold font (the default) you can say:
.ansi_yellow.ansi_bright { color: #FF7; font-weight: inherit; }

If you want several behaviours in the same html you can use css magic like that:
.my_own_ansi_enviroment .ansi_inverse { font-style: italic; border: none; }

I look forward applying it to TestFarm soon so all the miss-conversions are fixed.

Update: During my first search i didn't notice ansi2html. It is quite similar to deansi.

Update 2: Now its applied to testfarm, take a look at the output by clicking on one of the red executions (which should not exist but shit happens).

Tuesday, September 6, 2011

CLAM binders, ipyclam and PyQt

I just finished a pair programming session with Xavier Serra. He is going to defend his Final Career Project on Friday and we are preparing some cool demos involving binding ipyclam and pyqt. It has been an exciting session because as we debunked one by one the show stoppers that we were finding, we realized that the potential of the tool mix is wider than we thought.

What we can do now is to build a network with ipyclam, building an interface by combining pyqt and ui files and binding them to that network, all that either in live by using the interactive shell or using a written script. This formula adds the flexibility of scripting to CLAM prototyping system, raising the ceiling of what you can do without raising too much the learning threshold.

For example, let's play a file in a loop with ipyclam:

import ipyclam
n=ipyclam.Network(ipyclam.Clam_NetworkProxy())
n.file = n.types.MonoAudioFileReader
n.out = n.types.AudioSink
n.file.Loop = 1
n.file.SourceFile = "jaume-voice.mp3"
n.file > n.out

n.backend="PortAudio"
n.play()

Then you can instantiate an Oscilloscope, bind it and play:

from PyQt4 import QtCore, QtGui
a=QtGui.QApplication([])

w=n.createWidget("Oscilloscope")
w.show()
w.setProperty("clamOutPort", "file.Samples Read")

n.stop()
n.bindUi(w)
n.play()

You can also load an UI file and bind it simultaneously..

w2 = n.loadUi("myui.ui")
w2.show()
n.stop()
n.bindUi(w2)
n.play()

Adding a tonal analysis and some related views

n.stop()
n.tonal = n.types.TonalAnalysis
n.file > n.tonal
w3 = n.createWidget("CLAM::VM::KeySpace")
w3.setProperty("clamOutPort", "tonal.Chord Correlation")
n.bindUi(w3)
w3.show()
n.play()

The enabler of the mix has been the new binder architecture in CLAM. Until 1.4, the Prototyper used what we call 'binders' to relate processing elements with user interface elements. Each binder concentrates in a given kind of binding: oscilloscopes, control sliders, transport buttons...

For the upcomming CLAM 1.5 the binder interface (CLAM::QtBinder) has been redefined and moved out from the Prototyper to the qtmonitors module. So now you can use them in any CLAM application. The bindings are now based on Qt dynamic properties which provide more flexibility than former QObject name mangling.

Currently there are several binders implemented:
* Action/Button -> launch a configurator dialog on some processing
* Action/Button -> launch a open dialog for a MonoFileReader
* Checkable -> Send a bool, or a bistable float control
* Slider -> maped float/int control
* Any Monitor -> outPort to monitor
* ControlSurface -> Send pair of controls
* Slider -> ProgressControl or a MonoFileReader or similar to control

Now you can extend those binder by means of plugins as we extended processings. You can use Qt dynamic properties in the interface elements to specify how the binding is done.

The abstract interface provides the static method QtBinder::bindAllBinders() which is the one called by python bindUi. This looks for every ui element in the QObject hierarchy, looks for every registered binder and if they match it is applied.

To implement your own handle you just have to rewrite the bool handles(QObject*) method that returns true if the object managed by the binder (type, name, presence of properties...) and the bool bind(QObject * uiElement, Network &amp; network, QStringList &amp; errors) which does the actual binding. To register the binder, you just have to instanciate one as static variable of a cxx file in your library.

All that is still being building up but its potential seems clear, so i hope that this new way of claming will be useful to you all.

Saturday, February 26, 2011

ipyclam: interactive python console for CLAM networks manipulation

Xavier Serra (not the MTG head, but an homonym student at the UPF) is about to reach an interesting milestone on his Final Career Project related to CLAM. He is developing an interactive Python console for CLAM named ipyclam. It is a text based interface to explore and manipulate CLAM networks. Hopefully this will end being a dock widget within the Network Editor but it is also useful as interactive text console tool and as programming interface, which are the first useful outputs Xavi is about to get. ipyclam comes to cover the need of manipulating complex networks in cases when point and click is just tedious and also that of generating parametrized networks.

Let's make clear that it is not a full wrapper for the CLAM API like Hernan's pyclam, ipyclam just enables high level operations you usually do with Network Editor: instantiating, connecting, configuring and playing modules. Moreover we have intentionally decoupled ipyclam API to any existing CLAM API in order to define the most pythonic, convenient, and clean API we could think. For example the code to build an stereo cable would be:

net = Network()
net.processing1 = net.types.AudioSource
net.processing1.NOuputs = 2
net.processing2 = net.types.AudioSink
net.processing2.NInputs = 2

net.processing1.Output1 > net.processing2.Input1
net.processing1.Output2 > net.processing2.Input2

net.play()

An interesting feature, is that network.code() just returns an string with similar python code, so a network knows how to regenerate itself. This opens the door to python based format for CLAM networks. Bye bye XML!.

Convenience? Yes, please. Connections can be done in batch, broadcasting connections from all the connectors in one processing to all or to a single connection of another:
net.processing1 > net.processing2 # all to all
net.processing1.Output1 > net.processing2 # one to all
net.processing1 > net.processing2.Input1 # all to one

Convenience is good but all things should be doable. Often most convenient solution is not the best suited for all the cases. Accessing configuration parameters and connectors of any kind directly from proccessing is quite convenient but names can collide, to solve that some special attributes are provided to restrict the name scope.
network.processing1._config.NOutputs
network.processing1._inports.InPort1
network.processing1._outports.OutPort1
network.processing1._incontrols.InControl1
network.processing1._outcontrols.OutControl1

Connection names can have spaces, and attributes cannot, so we also provide an alternative subscript syntax.
net.processing1['Output 1']

One of the features I like the more is tab key exploration.
  • network.[tab] and you get the list of processings
  • network.processing._inports[tab] and you get the list of input ports
  • network.processing._config[tab] and you get the list of configuration parameters
  • network.processing.[tab] and you get connectors and cofiguration parameters
  • network.types.[tab] and you get the list of available processing types

It works for interactive console with tab completion like ipython. We also provide ipyclam_console, an ipython based shell conveniently importing modules and adding a network to start playing with.

For more details on the API just check this document.

The implementation


ipyclam is defined in two layers. The front-end layer, purely written in python, makes the convenient API happen: Exploration, dynamic object attributes, many interfaces to similar operations... This upper layer, relies on the lower, less pythonic and more purpose oriented one, the network proxy layer, which provides access to the state and operations of the actual network with quite fewer entry points.

Xavi defined the front-end layer while evolving, in parallel, a dummy proxy layer simulating network status with basic python structures. That gave us the flexibility to explore and evolve both the frond-end and the proxy interface without bothering about the actual CLAM implementation that would have made such exploration quite rigid.

Two layers approach is also convenient because by defining the ops in the network proxy layer, we are able to reuse the front-end API with any other patching like environment. I am thinking on JACK or environments like ingen.

Status and road map


Xavi just finished most important bits of the API: Inspection, module creation, module type enumeration and module inter-connection. Currently we still rely on a dummy network proxy, but a CLAM based proxy will arrive during next week. Configuration API seems to be controversial and we are holding it until we have something implemented with CLAM.

Once we have a full CLAM based proxy the next big goal is to integrate the console in NetworkEditor. We need a console widget for Qt which is able to execute a python interpret. We found some candidates:
  • qconsole which already has a python wrapper
  • qtermwidget a more robust console (based on KDE Konsole) but without direct support for python, and
  • ipython qt frontend quite experimental and using a weird threading model, but still interesting as ipyclam_console already uses ipython and it is awesome

So either candidate seems to require some work on our side.

Well, I hope you will find this new CLAM feature as amusing as I do. Xavier is really doing quite a good job, congrats and keep it that high.

Wednesday, February 16, 2011

Numpy arrays to video

I found some examples on how to generate video with python by piping frames to external programs like ffmpeg or mencoder. All those snippets encode each frame as a given image format (png, jpg...) by using PIL, matplotlib.. to get them. Besides the dependency, building figures or encoding images can be quite slow. I finally found a way of piping raw numpy buffers as frames to mencoder. You can use the following code:


import subprocess
import numpy as np

class VideoSink(object) :
def __init__( self, size, filename="output", rate=10, byteorder="bgra" ) :
self.size = size
cmdstring = ('mencoder',
'/dev/stdin',
'-demuxer', 'rawvideo',
'-rawvideo', 'w=%i:h=%i'%size[::-1]+":fps=%i:format=%s"%(rate,byteorder),
'-o', filename+'.avi',
'-ovc', 'lavc',
)
self.p = subprocess.Popen(cmdstring, stdin=subprocess.PIPE, shell=False)

def run(self, image) :
assert image.shape == self.size
# image.tofile(self.p.stdin) # should be faster but it is indeed slower
self.p.stdin.write(image.tostring())
def close(self) :
self.p.stdin.close()


It is a tenth faster than the PIL based one. And there is no fair comparison to the matplotlib one. I got it working with mencoder but I could not figure out how to make it with ffmpeg.

You can find that code with an usage example there. Being based on other public domain snippets consider it also public domain.

I am using that class to save the output of my Freenect based project. More on that on next entries.

Wednesday, November 19, 2008

Refactoring script for CLAM networks

Now that the CLAM NetworkEditor has become such a convenient tool to define audio processing systems, we started to use it massively instead of C++ code to integrate processings. Even thought, we started to find that whenever we change a configuration structure, a port/control name, or even a processing class name, the networks xml had to be edited by hand because they didn't load. That problem led us to avoid such kind of changes, which is not a sane option. 'Embrace change', agile gurus said, and so we did.

We have developed a python tool to support network refactoring. It can be used, both as a python module, or as a command line tool, to batch modify CLAM network files using high level operations such as:


  • Renaming a processing class name
  • Renaming a processing name
  • Renaming processing ports or controls
  • Renaming a processing configuration parameter
  • Removing/adding/reorder configuration parameters
  • Setting configuration parameters values

The script just does XPath navigation and DOM manipulations in order to know which pieces need to be changed. Each high level command is just a couple of lines in python.

We are starting to use it to:

  • Adapt to changes in the C++ code
  • Change network configuration parameters in batch
  • Provide migration scripts for user's networks

About the last point, we plan the next release to provide network migration scripts containing a command set such as:
  
ensureVersion 1.3
renameClass OutControlSender NewClassName
renameConnector AudioMixer inport "Input 0" "New Port Name 0"
renameConfig AudioMixer NumberOfInPorts NInputs
setConfigByType AudioMixer NInputs 14
upgrade 1.3.2


Still some short term TODO's:

  • Include the clam version in the network xml so that the ensureVersion and upgrade commands work.
  • Integrating also Qt Designer UI files in the refactorings
  • Add some other commands as they are needed

Happy CLAM networks refactoring!

Friday, November 14, 2008

Managing Audio Back2Back Tests

So long since last post, and a lot of things to explain (GSoC results, GSoC Mentor Submit, QtDevDays, CLAM network refactoring script, typed controls...). But, let's start explaining some work we did on a Back-to-back system we recently deployed for CLAM and our 3D acoustic project in Barcelona Media.

Back-to-back testing background



You, extreme programmer, might want to have unit tests (white box testing) for every single line of code you write. But, sometimes, this is a hard thing to achieve. For example, canonical test cases for audio processing algorithms that exercise a single piece of code are very hard to find. You might also want to take control of a piece of untested code in order to refactor it without introducing new bugs. In all those cases back-to-back tests are your most powerful tool.

Back-to-back tests (B2B) are black box tests that compare the output of a reference version of an algorithm with the output of an evolved version, given the same set of inputs. When a back-to-back test fails, it means that something changed but normally it doesn't give you any more information than that. If the change was expected to alter the output, you must revalidate the new output again and make it the new reference. But if the alteration was not expected, you should either roll-back the change or fix it.

In back-to-back tests there is no truth to be asserted. You just rely on the fact that the last version was OK. If b2b tests get red because an expected change of behaviour but you don't validate the new results, you will loose any control on posterior changes. So, is very important to keep them green or validating any new correct result. Because of that, B2B tests are very helpful to be used in combination of a continuous integration system such as TestFarm, that can point you to the guilty commit even if further commits have been done.

CLAM's OfflinePlayer is very convenient to do back2back testing of CLAM networks. It runs them off-line specifying some input and outputs wave files. Automate the check by subtracting the output with a reference file and checking the level against a threshold, and you have a back-to-back test.

But still maintaining the outputs up-to-date is hard. So, we have developed a python module named audiob2b.py that makes defining and maintaining b2b test on audio very easy.

Defining a b2b test suite


A test suite is defined by defining back-to-back data path, and a list of test cases, each one defining a name, a command line and a set of outputs to be checked:

#!/usr/bin/env python
# back2back.py
from audiob2b import runBack2BackProgram
data_path="b2b/mysuite"
back2BackTests = [
("testCase1",
"OfflinePlayer mynetwork.clamnetwork b2b/mysuite/inputs/input1.wav -o output1.wav output2.wav"
, [
"output1.wav",
"output2.wav",
]),
# any other testcases there
]
runBack2BackProgram(data_path, sys.argv, back2BackTests)




Notice that this example uses OfflinePlayer but, as you write the full command line, you are not just limited to that. Indeed for 3D acoustics algorithms we are testing other programs that also generate wave files.

Back-to-back work flow


When you run the test suite the first time (./back2back.py without parameters) there is no reference files (expectation) and you will get a red. Current outputs will be copied into the data path like that:
b2b/mysuite/testCase1_output1_result.wav
b2b/mysuite/testCase1_output2_result.wav
...

After validating that the outputs are OK, you can accept a test case by issuing:
$ ./back2back.py --validate testCase1
The files will be moved as:
b2b/mysuite/testCase1_output1_expected.wav
b2b/mysuite/testCase1_output2_expected.wav
...

And the next time you run the tests, they will be green. At this point you can add and commit the 'expected' files on the data repository.

Whenever the output is altered in a sensible way and you get a red, you will have again the '_result' files and also some '_diff' files so that you can easily check the difference. All those files will be cleaned as soon you validate them or you get back the old results.
So the main benefit of that is that the expectation files management is almost automated so it is easier to maintain them in green.

Supporting architecture differences


Often the same algorithm provides slightly different values depending on the architecture you are running on, mostly because different precision (ie. 32 vs. 64 bits) or different implementations of the floating point functions.

Having back-to-back tests changing all the time depending on which platform you run them is not something desirable. The audiob2b module generate platform dependant expectations by validating them with the --arch flag. Platform dependant expectations are used instead the regular ones just if the ones for the current platform are found.

Future


The near future of the tool is just being used. We should extend the set of controlled networks and processing modules in CLAM. So I would like to invite other CLAM contributors to add more back2back's. Place your suite data in 'clam-test-data/b2b/'. We should decide where the suite definitions themselves should be placed. Maybe somewhere in CLAM/test but it won't be fair because dependencies on NetworkEditor and maybe in plugins.

Also a feature that would extend the kind of code we control with back-to-back, would be supporting file types other than wave files such as plain text files, or XML files (some kind smarter than just plain text). Any ideas? Comments?

Wednesday, May 21, 2008

A configuration idiom for Python scripts

For our Python scripts we have used a fair number of idioms and variations such as importing a config.py file with the parameters as module global vars or importing the content of a dictionary. A different one we used lately is very useful and simple:


# This should be your program using the config

import os
class config :
#Here we define the default parameters
paramA = "value A"
paramC = "value C"
class category1 :
paramC="value sub C"

#Here we load new values from files, if they exist
for configFile in [
"/usr/share/myprog/defaultconfig",
"/etc/myprog.conf",
"~/.myprog/config",
"myconfig.conf",
] :
if not os.access(configFile,os.R_OK) : continue
execfile(configFile)

# That's the config params usage. Pretty!
print config.paramA
print config.paramB
print config.paramC
print config.category1.paramC
print "This is a template: %(paramC)s" % config.category1.__dict__


If you write in the config file this:

# myconfig.conf
paramA="new value A"
paramB="new value B"
category1.paramC="new subCvalue"
paramB+=" extension " + paramA

you'll get this

new value A
new value B extension new value A
value C
new subCvalue
This is a template: new subCvalue


The config file is read as you were adding code at the same indentation level you have on the 'execfile' call.

Notice the advantages:

  • Your config file looks like var assignations

  • You can use inner classes to build up categories

  • You can have a list of configuration locations with different precedence

  • You can include almost whatever python code

  • You can do templating with the params getting a dictionary like config.__dict__ or config.category1.__dict__

  • You can put config checking code after loading.


Be carefull on unreliable contexts:

  • Malicious config files can include almost whatever python code

  • Config syntax errors crash the program (i guess that can be solved)

  • Config files may add any new attribute, category, or method you didn't have


But if you are just managing your own utility scripts like us, that idiom is fantastic.

Tuesday, March 18, 2008

Command of the day: hotspot2calltree

Today, the command of the day is hotspot2calltree.

I do like a lot using kcachegrind to tune my C++ code. You can use KCacheGrind to navigate through the actual function calls in a given execution of your program and seeing very graphically where the time is spent.

Today i needed to optimize some python code but that's not C++ code. No problem. Add in your code this:


import hotshot
prof = hotshot.Profile("profile.hotspot")
prof.runcall(myFunction)
prof.close()

And then, at the shell:

sudo apt-get install kcachegrind-converters
hotspot2calltree -o profile.callgrind profile.hotspot
kcachegrind profile.callgrind

And now you get a nice kcachegrind profile you can navigate on.

Sunday, February 10, 2008

Comand of the day: kig

Each task has a tool. With graphics and figures too. If i want to edit a photograph or to perform some nice effects on an existing image, that's a task for Gimp. If I need some cute artwork for icons, banners, web... I prefer to vector with my so loved Inkscape. When such drawings are not so artistical and need some related and formal figures and diagrams, i normally consider dia, limited but correct. If i want to plot a complex graph i let the task to graphviz's dot and i just declare the vertexs. If I want to plot some program data output, python plus matplotlib is the faster way to process and render it. Automating execution to visualization process is very convenient. Some time ago I used gnuplot for that but python is more flexible towards data formats. Often what you need is to explore such data, interactive visualization can be revealing with tools such as qtiplot.

But my problem today wasn't none of the above but drawing some geometric diagrams (angles, vectors, tangents...) to illustrate some trigonometric equations. I was thinking on QCad but Kig did perfectly. Kig is about doing geometrical manipulation: intersections, angle transportation, angle mesurements, solidarized elements, python scripting...



I was to integrate kig png exporting into WiKo figure generation but i found two show-stoper problems: Command line options for batch exporting seems not to work and there is no way to control the viewport but by resizing the windows and controlling the zoom. While the concept of limited size canvas exists, I didn't find a way to resize it :-( Anyway is worth to dig in such a tool even doing patches to have batch exporting working.

Thursday, January 31, 2008

Impressions on Django (II): Development environment

On my previous post, I explained some basic ideas on how Django works. The post explained, mostly the programming model which is a clever implementation of the classical Model-View-Controller pattern. Not that new. But compared to other web development environments I worked with (PHP, Zope/Plone or plain mod_python), Django is a clear improvement because is both simple and pragmatical.

The programming model is something that has a direct impact on how you design the product, but there are other factors that determine how easy a developer can develop within a platform. In this post I arge about such factors, how Django afects the development workflow.

Editing and controlling source code

Compared to Zope, another python web application environment I've been fighting against, Django is a clear step forward to control your work.

First of all, the developer has the control of the source. Files are stored on the file system! It may seem an obvious assertion, but, if you have been using Zope you will know why I am so happy with that: Zope forces you to store all the code into a large binary file which acts as virtual filesystem. You cannot use a regular version control system such subversion to control your changes. ...and worst, it forces you to input code in web forms!! Argh!! Django ends with such a nightmare. Files are back to the file system and to your preferred editor.

Modularity

Still Django applications are modular in the same sense that Zope: you can combine several applications (modules) on a single site. For example, the administration interface is an application itself that can be used to edit any model of any installed application. You can disable it or enable it as a whole or for specific models. There is also an authentication application that can be used to transversally control the access to your application features. Every other application can use the authentication application to obtain information about validated users and to limit the access to certain features depending on the user profile. Session management and per-session storage, RSS feeds, SiteMap files, data mining interface... they all come for free, provided as applications. Besides the included applications, a nice application repository is available.

Debug cycle and exploration

Debugging your code is also very straight forward. While developing with Django, you are deploying a development Web Server not related to Apache, that you start from the console, and it is not visible from the outside. This enables each developer having her own instance of the web site. No administration passwords are needed and reloading is easier. Every message you print you'll get it in the console so it is ideal for debugging by tracing compared to using plain mod_python which runs on the apache server and you are to monitor the apache error log. Also, when some code fails with an exception, Django constructs a very handy web page with a lot of information: the back-trace enriched with code context, parameters and local variables inspection, all the environment values, the request values... All that available in a collapsible error web page. Lately I've been tempted of importing a failing python code into Django just to get such a big amount of information.

Also by running './manage.py shell' you get a python shell executed in the same conditions your code will be. Indeed the 'manage.py' script has very useful subcommands to infer model definitions from existing databases, to see database definitions from models, to import and export test data fixtures...

The next post

So yes, Django is a mod_python with gears and a Zope without the fat. However, while I don't regret choosing Django, it is not that perfect. On my next post, the last one on those first impressions on Django series, I will explain the problems we found while using the framework. The limitations we found and how it could be (is being) improved.

Well, maybe not the next post. Some other topics have appeared while writing this series of posts and they are likely to require an entry.

Sunday, January 20, 2008

Impressions on Django (I)

During the last months, I've been involved in a project on (text) information retrieval. The project required to develop a web interface over a python core and we chose Django as framework. Other option was using plain mod_python as we did for EfficiencyGuardian. But some time ago, in the context of the SIMAC project, Xavier Oliver, who was the responsible of implementing BOCA, CLAM Annotator's collaborative back-end, used Django and he was very enthusiastic on how rapid he had all the web working. So I wanted to give it a try for our current work. Here I am posting my first impressions as newbie django user. What Django has to offer?

Database abstraction


The most important part of Django is a persistent object model which maps python objects into database entities giving you a nice abstraction on the database layer. By defining such model classes, you get an object oriented programming interface to query and change related database tables, and even navigating and joining through relations as they were regular connected objects.

I normally dislike too transparent interfaces when they deal with efficiency sensible things such as database access. But Django states very clearly when and how such access is done allowing you to control it but using a high level object oriented idiom.

Administration interface


You can enable an existing administration module for your site. That is a web interface to create, edit and remove your model objects. You can control the way they are edited by adding extra properties to the model classes attributes.

Attributes have more types than real SQL types. Fields can be, for example, URL's, emails, telephone numbers or zip codes, and Django gives you for free custom validation and custom administration interfaces for them.

The administration interface also considers table relations providing, for instance, web interfaces for choosing related objects by foreign key and buttons to add a new related objects.

Application logic


Often, as in our case, the administration interface is pretty close to what the final application will be. But direct manipulation of a model is not enough for most web applications. Normally you need some additional application logic: Which functionalities are presented to the user, and which is the user dialog with the system to perform such functionalities.

Three elements are combined to build up such application logic in Django: URL mappings, views and page templates. URL mappings map regular expressions of requesting URL into calls to python functions. Such pỳthon functions are the views which perform the needed actions on the system and construct an output web page. Views usually inject python data into an HTML skeleton, the page template, to generate the response web page.

Django provides some convenience views to create, update, delete and listing model objects, also supporting common features such as pagination, date based browsing, validation and destructive action confirmation.

The next entry


Here i explained the basics of Django execution model. On the next entry i'll write some impressions on Django as development environment compared to other environments i used for web development such as Zope, mod_python and vanilla PHP.

Friday, January 18, 2008

BiBTeX Tooltip in html WiKo output

I was busy yesterday on providing better BiBTeX support for the HTML output in WiKo. I was adding bibliography tooltips. They were an original suggestion from Pau Arumi, and i agree with him that they will be very handy for reading an article in electronic format. The former html bibliography page is still available: just click instead of hovering.

To have it working, you should download the latest wiko version, install 'python-bibtex' debian/ubuntu package and appending to your css style sheet the latest statements of this css concerning 'bibref' class.

Then, just place any bibtex files on the same folder the wiki files are and refer a bibliography entry in the wiki files as '@cite:SomeBibtexId'. By 'WiKonpiling' you'll get both normal LaTeX bibliography and this html equivalent.

Take a look on the final feel at this chapter of my master thesis.

Saturday, December 15, 2007

Iterating properly in Python

After more than a year of python hacking you take a look at the official Python tutorial and still discover new ways of enhancing your code. Just two ways of saving list constructions on our actual code.

The first one: In our code, we are currently doing all the time something like this:


for key, value in myDictionary.items() :
doWhatEverWit(key,value)

This is not that appropiate because it creates the tuple list and then iterates. But if you do:


for key, value in myDictionary.iteritems() :
doWhatEverWit(key,value)

You just get fetched keys and values without creating any temporary list.

The other thing our code is full of is constructing a list using list comprehensions:


tempList = [expresionUsing(item) for item in collection]
for item in tempList: doWhatEverWith(item)

I knew about list comprehensions and i knew about generator functions. Generator functions are functions can be a iteration source by doing yield instead of return. yield returns a value but keeps the function execution state for the next call. That is a very interesting feature but i never used it because it is harder to create a function that yields than to create the loop itself.

But by reading the tutorial i found a brand new kind of expressions that sum up list comprehensions and generator functions: generator expressions. They have the same syntax than list comprehensions using parethesis instead of brackets, but instead of creating a list they create a source of iteration so that no temp lists are created. Previous code would look like that:


iterable = (expresionUsing(item) for item in collection)
for item in iterable: doWhatEverWith(item)

There are plenty of places in the code we generated last year (WiKo, TestFarm and build and utility scripts in CLAM where we can apply those two ideas. So i am pretty happy on having discovered that.

Thursday, December 6, 2007

WiKo, the wiki compiler

Pau and me have just released WiKo as sourceforge project. WiKo is a simple but powerful Python script that takes files with wiki content on a given directory and either builds a web, a LaTeX article or a blog.

The script has a very long history before being branded as WiKo. It has its roots on the simple script i did to build most of my websites (Can Voki, Codders, KKEPerians UNLTD...) The script eased keeping static a lot of pages sharing the same layout design. The script was later enhanced to read wiki pages and to build also LaTeX articles. Even I used it for my master thesis. Recently Pau also started to use it for his PhD thesis and he has added great improvements such as LaTeX formulas in HTML output or bibliography linking. And lately we started to use it as internal wiki for some projects we are involved within Barcelona Media. So we thought that such script deserved a sourceforge project, and that's how WiKo born. I hope it can be useful to you all.

WiKo might be useful to you if:

  • You have an static website and you are considering to make it dynamic just to reuse design
  • You have to write articles to be available in both html and pdf
  • You are moving content from web, to LaTeX articles and to blogs and you are feed up of translating markup
  • You love wiki syntax but you hate to edit wikis in web forms
  • You like LaTeX output but you hate (or don't know) its markup
  • You like colaborative environments such subversion and want to use it as base for a wiki
  • You still are considering ikiwiki but you would like it was not written in Perl so you could contribute to it ;-)

Also I am currently working hard on being able to use WiKo to edit this blog. I am almost there so stay tunned.