Monkey patch no Python

Hoje o @RodrigoSetti e o @watinha precisaram fazer um código muito louco que envolvia decorators para alterar a funcionalidade de um método de uma classe da biblioteca unittest.

Como eles não pretendiam alterar o pacote original, pois isso implicaria em bagunças catastróficas, eles prosseguiram com tentativa e erro, raça e uma pequena ajuda do Stack Overflow, até que o código funcionou. Eu que me envolvi um pouco na solução fiquei pensando o motivo da solução ter funcionado e como, então lembrei que havia um termo específico para o que eles haviam feito, monkey patch, ao chegar em casa decidi pesquisar sobre o assunto, o que me motivou a escrever esse post.

A pesquisa me levou a essa resposta linda do Stack Overflow e baseado nela que vou montar minha solução, ou seja, parecerá bastante com uma tradução da resposta mais votada.

No Python há uma leve diferença entre função e método.

>>> class Foo:
...     def bar(self):
...         pass
...
>>> def baz():
...     pass
...
>>> foo = Foo()
>>> foo.bar
<bound method Foo.bar of <__main__.Foo instance at 0x1004d29e0>>
>>> baz
<function baz at 0x1004b5f50>

Um método de uma classe é do tipo bound method, isto é, é uma função vinculada a uma instância de uma classe e consequentemente, por possuir esse vínculo, recebe o primeiro parâmetro self que é a instância da classe.

Callables que são propriedades de uma classe, ainda estão desvinculados, isso permite que você modifique a definição da classe como quiser.

>>> def life(self):
...     return 42
...
>>> Foo.life = life
>>> new_foo = Foo()
>>> new_foo.life
<bound method Foo.life of <__main__.Foo instance at 0x1004d29e0>>
>>> new_foo.life()
42

Há um porém nessa solução, ela modifica todas as instâncias da classe.

>>> foo.life()
42

É importante salvar a função atual em uma variável para retornar a classe ao original após o uso.

Se você inocentemente tenta assinalar a função como atributo de uma instância:

>>> def leet(self):
...     return 1337
...
>>> foo.leet = leet
>>> foo.leet()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: leet() takes exactly 1 argument (0 given)

Acontece que a função não é automaticamente vinculada a instância e portanto não recebe o self como esperado.

>>> foo.leet
<function leet at 0x1004b6f30>

Para vincular um método a uma única instância podemos utilizar o módulo new:

>>> import new
>>> foo.leet = new.instancemethod(leet, foo, Foo)
>>> foo.leet
<bound method Foo.leet of <__main__.Foo instance at 0x1004d29e0>>
>>> foo.leet()
1337

Desta vez outras instâncias não serão afetadas.

>>> new_foo.leet()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Foo instance has no attribute 'leet'

Esse é um verdadeiro monkey patch.

Vale lembrar que a partir da versão 2.6 do Python o módulo new está deprecated em favor do módulo types, então alteramos nossa solução para:

>>> def qux(self):
...     return "quux"
...
>>> import types
>>> foo.qux = types.MethodType(qux, foo)
>>> foo.qux
<bound method ?.qux of <__main__.Foo instance at 0x1004d29e0>>
>>> foo.qux()
'quux'

Por fim, uma outra opção é utilizar types.UnboundMethodType, que faz sentido, agora que sabemos o que é um método vinculado (bound).

Por hoje é só, até a próxima pessoal.

Nova fonte do Ubuntu 10.10 no 10.04

Ubuntu

Decidi não migrar para o Ubuntu 10.10 por dois motivos:

  • LTS (Long Term Support), o Ubuntu 10.04 promete suporte de 3 anos (a partir da data de lançamento) enquanto o Ubuntu 10.10 promete suporte de 1,5 anos
  • Novidades, foram poucas novidades que justificassem eu configurar todo meu ambiente novamente e não é exagero dizer que eu baixei, instalei e configurei muita coisa.

Todavia, eu achei a nova fonte livre Ubuntu muito bonita e atraente e queria colocá-la no meu Ubuntu 10.04, como foi bastante trabalhoso, pois a fonte não está disponível nas versões anteriores e o repositório não está com acesso público, vou postar aqui onde encontrei a solução.

A equipe do site webupd8 publicou uma cópia da fonte em seu repositório e para instalá-la basta:

sudo add-apt-repository ppa:webupd8team/ubuntu-font-family
sudo apt-get update
sudo apt-get install ttf-ubuntu-font-family

Depois da instalação, basta um clique com o botão direito no Desktop > Change Desktop Background > Fonts (aba) e selecioná-la como padrão.

Fonte: webupd8

Rails, por onde começar?

Se você, assim como eu, quando encontra uma tecnologia, ferramenta ou framework novo, não sabe por onde começar, para Rails uma boa referência é o livro Rails Tutorial (em inglês), disponível de graça na versão HTML e pago na versão PDF.

Rails Tutorial

O autor constrói uma aplicação do tipo Twitter com o leitor e utiliza diversos conceitos e ferramentas interessantes como:

  • RVM, permite a instalação de diversas versões de Ruby na mesma máquina.
  • Testes unitários, como testar seu model ou controller.
  • Testes de integração, como testar sua aplicação.
  • TDD, testes antes de escrever o código da aplicação, costuma simplificar muito as interfaces.
  • git, controle de versão descentralizado.
  • Mock-ups, criação de um rascunho da tela antes de construí-la, é implícito isso, mas você se acostuma fácil, o autor utiliza a fabulosa MockingBird.
  • Heroku, deploy simplificado em cima da plataforma do Heroku.

Além de ensinar o uso de Rails na construção de aplicações web. Em suma, é uma excelente referência e ainda há versões do livro tanto para Rails 2.3 como Rails 3.0.

Substituindo o Caps Lock por outra tecla mais útil

Um belo dia eu olhei pro meu teclado e vi uma tecla com excelente localização, onde meu dedo mindinho alcança sem esforço, mas que atualmente não oferecia nenhuma utilidade para mim.

Era ela a tecla Caps Lock ou “Fixa” em alguns teclados ABNT, dá pra contar na mão quantas vezes eu precisei digitar um texto todo em maiúsculo, pra ajudar, comecei a estudar como utilizar o vim no meu dia a dia, pra quem não sabe o vim é um editor de texto que dentre muitos outros detalhes faz bastante uso da tecla Esc que precisa de certo deslocamento da mão para ser alcançada.

Caps Lock

Sabia que no Ubuntu (Linux ou GNU/Linux) trocar uma tecla como a inútil Caps Lock por uma outra tecla seria fácil e me pus a procurar na internet, no fim acabei com um script simples que troca e destroca a tecla pelo Esc, caso um dia eu eventualmente precise dela, segue o conteúdo do script:

#!/bin/sh

case $1 in
        off)
                xmodmap -e "clear lock"
                xmodmap -e "keycode 0x42 = Escape"
                ;;
        on)
                xmodmap -e "keycode 0x42 = Caps_Lock"
                xmodmap -e "add lock = Caps_Lock"
                ;;
        *)
                echo "Usage: caps {on|off}, turn the caps lock key on or"
                echo "off.  When it is off, the key acts as an Escape key."
                ;;
esac

Salvei em meu home como caps_lock.sh e permiti a execução dele com chmod +x caps_lock.sh, feito isso adicionei a seguinte linha no meu .bash_profile (caso o arquivo não exista em seu home basta criá-lo):

~/caps_lock.sh off

Assim sempre que eu fizer login a tecla é trocada pelo Esc mas se no meio de uma sessão eu precisar do Caps Lock basta abrir um terminal e executar o seguinte comando ~/caps_lock.sh on.

Pra quem usa emacs a dica também é válida sendo mais interessante trocar o Esc pelo Control.

Trocando os ícones do Empathy

O Ubuntu 10.04 vem com o Empathy por padrão, que é um ótimo cliente, porém tenho a impressão de que os ícones são trocados Ausente era pra ser Ocupado e Ocupado era pra ser Ausente, pois munido de um pouco de tempo livre me pus a procurar como colocar ícones que ofereciam melhor usabilidade, já que eu me confundia todo com os ícones padrão.

Encontrei no OMG! Ubuntu[1] a solução, mas ao invés de substituir totalmente como o artigo indica eu coloquei os ícones em meu home no seguinte caminho $HOME/.icons/ inicialmente não tinha arquivos nessa pasta, após deszipar o arquivo[2] com ícones novos fiquei com uma pasta hicolor dentro de .icons.

Feito isso, basta reiniciar o Empathy e ter ícones muito mais lógicos, parecidos com o GTalk original. Veja como os ícones são claros e sem necessidade de legenda:

Ícones alternativos para o Empathy

[1] – http://www.omgubuntu.co.uk/2010/01/elementary-empathy-theme.html [2] – http://www.gnome-look.org/CONTENT/content-files/119449-elementary%20Empathy.zip