Tiago Cogumbreiro

O Irrepupável

Back to top

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

Friday, May 30, 2008

Simple Django handlers

Or, an example about introspection targeting Python's functions.

I really like the way CherryPy maps GET parameters to the parameters of the handling function (usually, methods). I miss this mapping in Django, therefore I implemented it. I am "lazy" and I did not search Django's API for something related to this — I did this for pleasure.

Anyway, I have implemented a decorator, params_from_GET that adds this functionality to Django-handlers. You have to read the docstring to read the usage.

Code dump (licensed under public domain):

import inspect
def get_func_args(func):
    """
    Returns a generators of pairs (parameter name, default value)
    of the target function.
    """
    (args, varargs, varkw, defaults) = inspect.getargspec(func)
    if defaults is None:
        defaults = ()
    offset = len(args) - len(defaults)
    return args[:offset], dict(zip(args[offset:], defaults))

def params_from(func, method, default_value=''):
    """
    Returns a decorator, see params_from_GET.
    """
    # get the default params
    args, params = get_func_args(func)
    if args[0] != "request":
        raise TypeError("First parameters needs to be 'request'")
    for param in args[1:]:
        params[param] = default_value=''
    
    def wrapper(request, **orig_kwargs):
        # copy the parameters
        kwargs = params.copy()
        # get the map for the defined method, e.g GET
        method_dict = getattr(request, method)
        # set the request object
        kwargs['request'] = request
        for key in params:
            # fill with values that were sent by the user
            if key in method_dict:
                kwargs[key] = method_dict[key]
        kwargs.update(orig_kwargs)
        return func(**kwargs)
    return wrapper

def params_from_GET(func):
    """
    The decorator pics up a handler function and fetches the
    values from the GET map.

    For example:

    @params_from_GET
    handler(request, foo, bar):
       pass

    Is the same as:

    handler(request):
       foo = request.GET('foo', '')
       bar = request.GET('bar', '')
    """
    return params_from(func, 'GET')

Update: added support for the keyword arguments that may be passed to the dispatcher by urls.py.

Saturday, March 29, 2008

Django and Unicode

I have made this patch against Django SVN r7379, please have a look at it:

--- /usr/lib/python2.5/site-packages/django/http/__init__.py    2008-03-29 22:24:02.000000000 +0000
+++ __init__.py 2008-03-29 22:23:03.000000000 +0000
@@ -360,10 +360,8 @@
         return self
 
     def next(self):
-        chunk = self._iterator.next()
-        if isinstance(chunk, unicode):
-            chunk = chunk.encode(self._charset)
-        return str(chunk)
+        chunk = unicode(self._iterator.next())
+        return chunk.encode(self._charset)
 
     def close(self):
         if hasattr(self._container, 'close'):

Before the patch, a chunk (the reply that will be sent by the HTTP server to the client) is encoded with the charset defined in our project (self._charset) only if it is an unicode object, otherwise, it will happily convert to a string using the system's encoding (by using the function str), which was resulting in a UnicodeEncodeError exception that would break Django.

If you want to make sure that the reply you are sending, through your HTTPResponse, is encoded into a string using the project's encoding, then convert it first into a unicode object. If my patch is accepted, though, this will be done automatically for you.

Oh, by the way, I am enjoying Django. I am using it to create REST web-services. It is being an enjoying and out-of-your-face experience.

Thursday, August 16, 2007

A look inside the architecture of Serpentine: operations

The cornerstone of Serpentine is an operation that is an asynchronous code execution that can be started and that eventually finishes. Operations are observable; when an operation finishes its listeners are warned.

class MyListener(object):
    def on_finished(self, evt):
        print evt.source, 'has finished', evt.is_successful

op = SomeOperation()
my_listener = MyListener()
op.add_listener(my_listener)
op.remove_listener(other_listener)

Operations can terminate in three different states: successful, aborted, and error. There is an attribute, in the finished event object, for each state (e.g., is_aborted).

Operations can be composite with the help of OperationQueues. These are used throughout the code to create complex operations that are well separated in possibly reusable parts. This is an example of the usage of an operation queue:

queue = OperationQueue([op1, op2])
queue.append(op3)
queue.insert(0, op4)
assert len(queue) == 4
queue.start()
# wait a bit...
queue.stop()

Queues also trigger the event before_operation_starts. Listeners that implement a method with that name are called with two arguments the event and the operation getting started. Notice that objects wanting to listen to that event must also use the method queue.add_listener. Listeners that do not implement the method with the name of the event being triggered are simply skipped. Exceptions raised by listener's methods do not interfere with the dispatching.

When implementing an operation there are some things you must extend: the attribute is_running and the method start, which should start operations in a new thread or in a gobject.idle_add.

This is the code listing of a simple class of serpentine.operations:

class CallableOperation(Operation):
    can_stop = False
    running = False
    
    def __init__ (self, func):
        super(CallableOperation, self).__init__()
        self.func = func
    
    def start (self):
        gobject.idle_add(self._send)
        self.running = True
        
    def _send(self):
        try:
            self.func()
            self.running = False
            self._send_finished_event(SUCCESSFUL)
        except Exception, err:
            self.running = False
            self._send_finished_event(ERROR, err)

The helper method _send_finished_event notifies listeners with a FinishedEvent, which must be issued when an operation finishes. This class turns a function into an operation. This operation should not block for a long time or it will freeze the UI, remember it is being called in Gtk+'s main loop (through gobject.idle_add).

Another type of operation is a MeasurableOperation. Extending classes must implement the attribute progress. An OperationQueue is a MeasurableOperation. Instances of MeasurableOperation are well integrated with a generic progress window that exists in the module serpentine.gtkutil. For example, when the user clicks on the write button, an operation ConvertAndWrite is created. This operation, amongst other things, is a queue of two operations: FetchMusicList and WriteAudioDisc, each of which a composite of other operations. The structure (e.g., the children) of the operation ConvertAndWrite may change during time, for example if we add normalization to the process, but the progress window and the other parts of code that interact with ConvertAndWrite are not affected by this change.

Wednesday, August 15, 2007

Serpentine 0.9 Released!

Serpentine 0.9 was released! Download in bz2, or in gz.

Here is a quick changelog:

  • Support for totem-plparser 2.19 (#463180).
  • Set the device from the command line and make it persistent (#333281).
  • Able to write the same file more than once in the same playlist (#465352).
  • Files can now be removed from the list while recording (#345270).
  • When cache location is unavailable allow the user to select another (#382145).
  • Serpentine now inhibits suspension while recording, via GNOME Power Manager. Contribution from Matthew Martin (#344948).
  • Mastering widget is now aware of the two seconds gap between tracks (#344689).

For more information read the full release page. List of fixed bugs:

Next minor release will be for translations. So keep 'em comming!

Friday, August 10, 2007

Seeking out beta-testers for Serpentine

I am aware that TDD would probably avoid this plea for help, but I digress. I am in dire need for beta testers for Serpentine. I am tackling bug #345270 from the bug list for the next release:

  • #333281: Persistent options
  • #345270: Removing WAVs during recording may ruin it
  • #463180: New totem.plparser API
  • #465352: Cannot record if the same file is listed twice

The only thing you need to do is try to run latest development version and write a CD with Serpentine. My CD recorder is not recognized by Ubuntu, so I cannot test my latest changes. The development version is available at:

http://bazaar.launchpad.net/~cogumbreiro/serpentine/main

If someone helps out fast I will make a release and postpone #465352, since that obligates me to install alot of packages from source or install Gutsy.

Friday, August 03, 2007

Fixing Serpentine's bugs

Next release of Serpentine is very soon. It will probably be version 0.9, where no features will be addressed, only bug fixes. These are the bugs that will be fixed to meet the goal (i.e., the release):

  • #463180: Update code to the new API totem.plparser
  • #463196: Crash cause by ValueError in insert_before() (postpone: NEEDINFO)
  • #463191: Crashed by an AssertionError in _get_progress()
  • #345271: DND to other apps removes the dragged track (postpone: have no idea how to fix it)
  • #345270: Removing WAVs during recording may ruin the recording process
  • #460584: Burning speed preference does not work (postpone: WORKSFORME)

Do you wan to help out? Most of these bugs are really simple to fix and I will mentor you in the process. Curious? Just look at the list of open bugs in GNOME's Bugzilla or the list of open bugs in Launchpad (thanks Gothicx).

Wednesday, August 01, 2007

Serpentine moving to Launchpad

After a long time without any contribution to Serpentine, I have taken over its maintenance and began cleaning up bug reports.

I have been exposed to bazaar thanks to Pida. Its workflow is very easy to learn and very powerful. I have also used it to manage local projects and projects from school, because it needs no server. Serpentine is now moving its repository from Subversion over to Bazaar. The new development branch is:

http://bazaar.launchpad.net/~cogumbreiro/serpentine/main

I am also going to start using less the project page of berlios and start using more the project page of launchpad. The bug tracking is still going to be GNOME's bugzilla.

I intend (but maybe I won't) to have more than one release very soon. I am planning to release Serpentine 1.0 before the end of August. Version 1.0 will focus solely in the correction of defects (no features will be addressed). Serpentine is still looking for a new maintainer with more time!

Tuesday, July 24, 2007

When to use the decorator classmethod

The classmethod may be confused with Java's modifier static. These two, however, are really different. Static methods work like functions (remember Java obligates everything to belong to a class). Class methods work like methods, but their self (i.e., the first parameter) is the class where the method is bounded to. Class methods are great to implement factories of objects, since the first parameter can be used to create instances. Hence, the use of class methods should be avoided when a simple function can suffice, which is when the first parameter (the class) is not needed.

Sunday, April 22, 2007

Cogumbreiro's code trunk.

Introducing: Cogumbreiro's code trunk. This is a project I have started some weeks, maybe months, ago. I will keep Python modules I develop[ed]. Someone might find them useful in the future (especially me). The license is pretty liberal; it is MIT.

When I become bored, I will start writing / blogging about / documenting the source code. These modules are mostly in the level of recipes or quick hacks. BTW, Google's project hosting rocks, still haven't played with the issues manager though.

Monday, November 20, 2006

Link Flood, Part 2

Good Math, Bad Math é um sítio muito interessante onde se encontram linguagens de programação difícieis por natureza, originais e que valem pelo engenho de quem as criou, exemplos interessantes são: programar com cores e programar com números primos.

O Ali, autor do projecto Pida, tem um blogue muito interessante. Ultimamente tem falado sobre Zope, PyGtk e Kiwi. Um dos seus últimos artigos faz uma breve apresentação de um módulo do meu projecto Rat, o título é Rat, more easy PyGTK dialogs.

Também sobre Gtk+, Rodney Dawes, um GNOMEr, explica como tornar os ícones de uma aplicação temáticos.

Para quem se interessa sobre temas científicos, em geral, o sítio CiteULike é como um Del.icio.us para artigos científicos, livros e relatórios com toda a metadata que lhe está associada. Uma característica muito interessante é a possibilidade de fazer upload de PDFs. Este espaço de armazenamento online dá-me muito jeito uma vez que posso fazer upload dos documentos que encontro na ACM e que só posso descarregar na universidade.

Um “truque” muito interessante, ensinado pelo Jamin Gray, é o de calcular, mentalmente, o dia da semana a partir de uma data.

Também sobre a mente – mas neste caso de um modo ridículo – num concurso de televisão francês, o concorrente é perguntado sobre algo descoberto no século XVI. Vejam o filme e divirtam-se! :)

Se forem engenhocas, poupem uns trocos e construam um emissor FM para o vosso sistema de som!

Quando vos apetecer ser pouco produtivos então consultem este sítio, I Am Bored.com. É actualizado constantemente com filmes e imagens muito engraçadas e esquesitas.

Friday, October 20, 2006

Pattern Matching on Python Decorators

I have implemented an illustratory pattern matching library decorator for Python. Just download matcher.py and play with it yourself.

What can I do with it?

You can do basic pattern matching for simple values. The following example shows you what you can do with lists.

from pattern_matching import *

@pattern_matching
def print_list(a_list)
    """prints a list, element by element"""

@print_list.dispatch(lst[_:_])
def _at_least_one(a_list):

print a_list[0] print_list(a_list) @print_list_dispatch([]) def _empty_list(a_list) print "done!"

The lst variable is a special one and is used for using Haskell-like syntax on Python, the slice object represents head and tail of a list. The _ variable represents the any element, just like on the other language too.

Note: This is just an example of what you can do with decorators, it’s not supposed to be a multi-dispatch library, if you want one use the excelent dispatch module.

Wednesday, September 20, 2006

Python 2.5!

Yay! Python 2.5 já está disponível :)

As grandes novidades são:

  • Com o operador with abrir o ficheiros, utilizar fechos de threads ou manipular cursores de bases de dados passa a ser mais simples.
  • Passa a ser possível enviar parâmetros para os geradores. O que me faz pensar o quão simples a implementação do cálculo pi pode ser usando esta linguagem.
  • O condicional – exemplo: food = spam if not hungry else spam_and_eggs – que vai tornar o código mais legível.
  • Um módulo para definir funções parcias, os fãs do Haskell podem se sentir um pouco mais em casa.
  • O tratamento de excepções está mais agradável: podemos definir um else para saber quando não foram lançadas excepções. Agora todas as excepções passam a ter uma excepção base.

Entretanto, ando a aprender a trabalhar com o AUCTeX e com o Emacs. Wish me luck ;)

Sunday, September 10, 2006

Já em Lisboa

Este é o meu segundo fim-de-semana em Lisboa e o primeiro com disponibilidade para fazer o que me apetecer. Na primeira semana tive a arrumar o apartamento e a fazer as tarefas chatas do quotidiano de qualquer pessoa que vive sozinha (lêr: sem ninguém que as faça por si).

Sexta-feira fui ao bairro alto, foi muito engraçado. Havia montes de gente, mais gente do que todas as outras vezes que tinha lá ido — eram dias de semana. Acabei por encontrar pessoal que já conhecia das ilhas (outros que nem tanto, mas do mesmo local) e a noite perdurou, ao som do sotaque micaelense, até às 6:30 da manhã! Sim, porque tive a brilhante ideia de ir de metro (o primeiro do dia seguinte) para não pagar o táxi. Note to self: don’t do it again ;)

O trabalho que estou a fazer é um compilador de uma linguagem de cálculo-pi, feito em Java, seguindo o livro do Appel. Estou a fazê-lo na FCUL e o local é fantástico, tem bastantes condições e o pessoal que lá trabalha é muito simpático e acolhedor.

A consequência disso é que tenho lido mais papers que alguma vez pensei fazer (durante uma licenciatura). Já decorei nomes como Milner ou Sangiorgi. Aprendi até como fazer a codificação dos números usando canais de comunicação.

Também estive a descobrir quem foi o primeiro a citar a implementação do padrão Visitor usando a introspecção num documento “relevante”. O que me levou a um sítio muito interessante o Hillside Group, onde fazem conferências muito apelativas.

Também foi interessante relembrar o Java a sério, interessante perceber que não me foi difícil voltar a este, vindo de anos de Python, e que a experiência com uma linguagem mais dinâmica enriqueceu-me de uma maneira que desconhecia.

Por exemplo, a estória do visitor com recurso à introspecção veio de uma implementação que fiz, de um modo espontâneo, que necessitava uma referência. Esta implementação não é muito utilizada no “mundo do Java” mas natural no “mundo do Python”.

Podermos evadirmo-nos da barreira dos tipos, de quando em vez, aumenta a nossa flexibilidade e produtividade de uma maneira bastante eficaz que deveria ser mais enfatizada na comunidade.

Mas sobre esse assunto mais escreverei assim que colocar o artigo que estou a escrever online, sobre o estudo de diferentes implementações do dito padrão.

Sunday, July 02, 2006

Homepage internals

Let me introduce the way the script that generates my homepage works. It can create two types of content, one trough files that exist on a certain directory and the rest is computated data.

Today I’m going to talk about the ones generated by real files and what I want to do with them.

I have a directory which is walked upon and each file is matched against a processor. That processor will be asked if it can handle the file and will create the appropriate content if it does.

The power of this system lays in the ability to extract metadata. Currently I have two types of processors: HTML and reST.

The HTML processor filters the data through Tidy and the metadata it can extract is the title and the body. Here is an example of a document:

<html>
  <head>
    <title>Document 1</title>
  </head>

  <body>
  Hello world!
  </body>
</html>

And the processed data is (in python):

{
  'title': 'Document 1',
  'body': 'Hello world!',
}

In the future I’m going to implement tags, which on the HTML world are known as keywords.

To do so, I will include a HTML tag meta in the head section. These keywords will also be included in the generated file and will be used in a tag listing for all the documents that I’ve created.

Here’s an example of a document with a few tags filled:

<html>
  <head>
    <title>Python is cool</title>
    <meta name="keywords" content="Python, Linux" />
  </head>

  <body>
  I like Python, Linux and Open Source.
  </body>
</html>

And the generated metadata:

{
  'title': 'Python is cool',
  'body': 'I like Python, Linux and Open Source.',
  'tags': ('Python', 'Linux'),
}

After this I can also specify the language of the document, a short summary (using the description) or any other metadata information commonly [un?]used on webpages.

Luckly enough reST files can also include this type of metadata, thus I will be able to include the same level information on this format as well – I say ‘luckly’ because I intend to use reST to create my documents from now on.

Monday, June 19, 2006

Progresso na Homepage 2.0

Fiz algum progresso no meu novo e melhorado sítio. Instalei o Django e, 5 minutos depois, percebi que não era para mim. Agora não preciso de uma framework mas sim de uma biblioteca (vide Library or Framework? de Guido van Rossum).

Estou a precisar de uma aplicação com uma curva rápida de aprendizagem. Uma vez que já conheço a maioria das bibliotecas que constituem o projecto TurboGears foi nesse que decidi investir mais tempo.

Duas tarefas que quero fazer, por agora, são: criar um arquivo com o meu blog antigo e criar uma secção para artigos.

Comecei pela segunda tarefa, criei uma pequena função que utilizando o endereço pedido mapeia-o em relação ao sistema de ficheiros e obtém um ficheiro com o conteúdo da página pedida. Parecido ao modo de como o Apache publica as suas páginas.

Dependendo da extensão é verificado se existe um processador que o interprete e gere HTML através do conteúdo existente no ficheiro. É de notar que é apenas a secção principal das páginas, o visual é partilhado através do mesmo template.

Por ora tenho 3 processadores: texto normal, HTML e reST.

Uma vez que vi a coisa a funcionar razoavelmente bem e como queria de adicionar mais algumas funcionalidades criei uma classe onde coloquei a função utilizada como um método da nova classe. Criei, de seguida, um método para listar todos os recursos existentes.

O interessante é que no futuro não pretendo utilizar o CherryPy — servidor web utilizado pelo TurboGears — para mostrar o sítio final. Vou usá-lo apenas para prototipagem das bibliotecas entretanto criadas que depois serão usadas para gerar um sítio estático.

Daí a necessidade da listagem de artigos existentes vou precisar de saber que ficheiros tenho de criar.

Falta-me agora começar a pensar nos breadcrumbs — ou migalhas de pão ;) — de modo a poder-se navegar facilmente nos vários artigos existentes.

A segunda tarefa é gerar um arquivo com o meu blogue antigo. Já consegui instalar a base de dados antiga e, através de engenharia reversa, estou a tentar reconstruí-lo. Até agora o único problema que estou a ter é não ter ainda encontrado a data das entradas — a verdade é que também não perdi muito tempo a fazê-lo.