Trabalhando com Python e Django à moda Osvaldo
Esse post está aqui para ser usado por mim como referência futura mas, como pode ser útil para outras pessoas vou deixá-lo público aqui no blog.
Software
Trabalhei muito tempo com Linux (e alguns outros Unices) e de três anos pra cá sou mais um Apple Fanboy que usa o excelente OS X. Mas acho que boa parte das dicas aqui ainda são úteis para usuários de Linux.
- Terminal.app – Porque Mac é máquina pra ‘macho’ :D
- bash – Pesadão, bloat, mas não consegui me habituar com outro. É o default do OS X.
- Vim – Esse é o editor pra tudo. É difícil de aprender a usar mas é um F1. Depois que aprendemos a lidar com ele a gente voa. Uso a versão texto que acompanha o OS X.
- TextMate – Esse eu uso para o desenvolvimento ‘pesado’. Dá pra usar o Vim pra isso também. Mas dependendo do meu humor eu escolho o TextMate para algumas coisas.
- Rudix – O OS X não vem com tudo mas você encontra o que falta no Rudix.
- Git – Uso o git pros meus projetos mas também tenho o Mercurial, Bazaar, Subversion, … instalados para contribuir com outros projetos open-source
- virtualenv – ter um ambiente isolado para cada projeto Python onde você trabalha é muito legal. Já escrevi sobre o virtualenv aqui.
- pylint e pyflakes – Analisadores estáticos de código.
Diretórios básicos
- $HOME/
- Work – Diretório onde os projetos em que trabalho ficam.
- bin – Diretório com scripts, binários estáticos, etc. Esse diretório fica no $PATH
Configuração
Sempre que eu falar sobre um arquivo de configuração específico você pode encontrá-lo no endereço: http://github.com/osantana/personal.
Os arquivos ‘.’ (ponto)
- Configurar 3 aliases: mv='mv -i' e cp='cp -i' pra evitar acidentes com arquivos sendo sobrescritos e ls='ls -G' para habilitar cores no comando ls.
- Configurações genéricas para cores no terminal
- Definir o vim como EDITOR padrão.
- Definir LANG e LC_CTYPE como en_US.UTF-8 para que o Mercurial e alguns outros softwares funcionem corretamente.
- Adicionar o diretório $HOME/bin ao $PATH. Nesse diretório eu jogo todos aqueles programinhas utilitários usados no dia a dia.
- Configurações Python:
- export PYTHONSTARTUP="$HOME/.pystartup.py"
- source ~/bin/django_bash_completion
- Configuração Java: export JAVA_HOME="/Library/Java/Home"
- Configuração Ruby: adicionar $HOME/.gem/ruby/1.8/bin ao $PATH
- Eu uso virtualenv em todos os meus projetos então crio duas funções para ativar os ambientes e entrar nos diretórios desses projetos:
# Uso: p nome_do_projeto p() { cd ~/Work/$1* [ -f bin/activate ] && source bin/activate } # Uso: c c() { [ -d "$VIRTUAL_ENV" ] && cd $VIRTUAL_ENV }
[user]
name = Osvaldo Santana
email = osantana na triveos.com
[color]
status = auto
diff = auto
branch = auto
ui = auto
grep = auto
[alias]
st = status
ci = commit
co = checkout
[merge]
tool = opendiff
[core]
legacyheaders = false
excludesfile = /Users/osantana/.gitignore
whitespace = trailing-space,space-before-tab
[apply]
whitespace = fix
[repack]
usedeltabaseoffset = true
[git-tmbundle]
gitx-path = /Application/GitX.app/
[mergetool "opendiff"]
cmd = opendiff
trustExitCode = true
[clean]
requireForce = false
.DS_Store *.py[co] *.tmproj *~ *.swp*
Eu uso o modo vi também no console. Neste arquivo fica essa configuração e mais umas outras que deixam o comportamento do prompt do Mac mais parecido com o do Linux.
Já falei sobre essas configurações aqui no blog. Use por conta e risco.
As configurações que eu uso para análise estática do código que eu produzo. Eu rodo o pylint antes de fazer o commit do meu código. Durante o desenvolvimento eu uso somente o pyflakes que é mais simples e rápido mas faz uma análise mais superficial do código. Eu costumava usar o pep8.py mas já faz um tempo que o aposentei.
Script executado pelo interpretador Python ao entrar no modo interativo. Eu configuro o ‘auto-completion’ do prompt interativo do Python, gravo o histórico de comandos, etc.
Infelizmente ele não funciona com o Python padrão do Mac porque o mesmo não é compilado com a biblioteca readline. Mas no Linux ele (deve) funcionar certinho.
Esse é o meu famoso arquivo .vimrc. Ele não tem nada de muito especial.
Outros arquivos
Existem outros arquivos mas, nestes casos, eles contém informações privativas e não faria sentido colocar aqui pra vocês :)
Criando e Usando um projeto Python (com Django)
Para exemplificar vamos criar um projeto “pythonologia”:
~ $ cd ~/Work Work $ virtualenv --no-site-package pythonologia New python executable in pythonologia/bin/python Installing setuptools............done. Work $ p pythonologia (pythonologia) pythonologia $ easy_install django (pythonologia) pythonologia $ django-admin.py pythonologia (pythonologia) pythonologia $ cd pythonologia (pythonologia) pythonologia $ git init (pythonologia) pythonologia $ git add *.py (pythonologia) pythonologia $ git commit -m "Initial commit"
Projeto criado e a estrutura de diretórios vai ficar mais ou menos assim:
~/Work/pythonologia
|____ pythonologia
| |____ app_django1
| \___ app_django2
|____ bin
|____ include
\___ lib
\____ python2.6
|____ distutils
\____ site-packages
Os arquivos que não são mantidos no repositório Git ficam no diretório ~/Work/pythonologia ou em um diretório ~/Work/pythonologia/files. O arquivo de projeto do Textmate, por exemplo, fica em ~/Work/pythonologia/pythonologia.tmproj.
Eu também crio um link simbólico ~/Work/pythonologia/django -> ~/Work/pythonologia/lib/pythonX.X/site-package/Django-1.1.1-py2.6.egg/django para dar uma ‘espiada’ no código do Django quando necessário.
Quando eu quero trabalhar num outro projeto eu faço:
(pythonologia) pythonologia $ deactivate pythonologia $ p outro_projeto (outro_projeto) outro_projeto $
Eu estou num diretório qualquer e quero voltar para o diretório raiz do projeto basta fazer:
(pythonologia) ~ $ c (pythonologia) pythonologia $
Python ainda é pythônico?
Eu estava lendo um (longo) artigo que fala sobre várias coisas sobre como desenvolvíamos software no passado e como desenvolvemos hoje, etc… E num determinado momento ele fala sobre bibliotecas, frameworks e sobre um conceito denominado por ele “radius of comprehension“.
O conceito de “radius of comprehension” é simples: dado um determinado trecho pequeno de código, quanto de código a mais você precisa ler para entender o que ele faz. Quanto menor o “radius of comprehension” melhor.
Ao ler isso eu me lembrei de uma palestra do Luciano Ramalho onde ele fala que gosta da linguagem Python (e da idéia de algo ser ‘pythonico’) porque ela “cabe na cabeça” dele e acho que isso tem uma relação direta com a idéia de “radius of comprehension“.
Eu também pensava da mesma forma que o Luciano. Achava que Python “cabia” na minha cabeça. Mas hoje eu devo admitir que isso é parcialmente verdade.
Em primeiro lugar eu acho que a linguagem vem crescendo demais desde a versão 2.2. Adicionando funcionalidades e “acúcares sintáticos” cujos benefícios podem ser facilmente questionados.
Mas não vou falar muito da linguagem não. Vou falar de alguns módulos da biblioteca padrão do Python que são praticamente impossíveis de serem usadas sem ter a documentação à mão:
- logging – esse é o pior de todos. Não tem uma única vez que eu não preciso recorrer à documentação do módulo pra fazer algo “bobo”. Sei que um “logging.log(…)” basta para o básico, mas se você precisa de algo básico+1 você já se vê obrigado a ler toda a documentação do módulo. Acho que o problema desse módulo foi tentar copiar o log4j do mundo Java. Todos nós conhecemos o gosto por “over engineering” dos programadores Java.
- ConfigParser – não tenho muito a dizer. Porque esse módulo precisa daqueles conceitos complicados de configurações “globais”, busca de arquivos em múltiplos diretórios, etc. Ele poderia implementar o simples e fácil e deixar as extensões para bibliotecas de terceiros.
- email – precisei usar esse aqui uma única vez e desde então eu tremo de medo sempre que alguém me pede pra “manipular e-mails” em uma aplicação Python. Sei que manipular e-mails é complicado se considerarmos a quantidade de “variações dos padrões” existentes num serviço que tem quase a idade da Internet, mas as abstrações devem ser construídas para nos poupar desses detalhes, não?
- xml.dom e xml.sax – eu já não gosto de XML, imagina manipular XML com essas duas bibliotecas “podres”. Se eu pego um código pra dar manutenção e esse código usa uma dessas duas bibliotecas eu triplico o valor do serviço.
- re – neste caso eu não acho que seja muito culpa do Python, mas peça pra alguém que conheça regex mas não conheça Python explicar a diferença entre re.search() e re.match(). Ou mostre pra ele uma regex com “(?P<foo>.*)” significa.
Além dessas tem outras que não vou me lembrar. Tem também algumas bibliotecas, módulos e frameworks no atual “eco sistema” do Python que simplesmente não entram na minha cabeça:
- Zope e Plone – a turma do PythonBrasil já conhece essa história. Eu tentei bem umas 3 vezes estudar essa dupla e nas 3 eu não consegui ir além de abrir a interface de administração do Zope. Mas de duas uma: ou sou burro demais ou o troço é desnecessariamente complicado. Por sorte o ZODB funciona separadamente porque esse sim é poderoso e fácil de usar.
- Buildout – esse eu já usei basicamente pra instalar alguns programas mas é uma caixa preta completa pra mim. Não tenho certeza, mas acho que ele nasceu no (ou em função do) Zope/Plone e talvez isso explique um pouco disso. Eu não sei direito se ele é um sistema de build, um sistema pra criação de ambiente de desenvolvimento, ou se é algum sistema alienígena de IA.
Eu sei que os problemas que temos que resolver hoje em dia são bem mais complexos do que os que tínhamos que resolver quando comecei a programar, mas problemas complexos não precisam de soluções que deixem transparecer essa complexidade.
Textmate “Django test executator tabajara”
O script a seguir pode ser usado para executar testes automatizados em uma aplicação Django a partir do Textmate.
Ele deve ser usado como um “command” no bundle “Python Django” do Textmate e funciona exclusivamente com o sistema de testes do próprio Django (manage.py test).
#!/bin/bash python=$(/usr/bin/which ${TM_PYTHON:-python}) project="$(dirname "$TM_DIRECTORY")" app="$(basename "$TM_DIRECTORY")" # virtualenv if [ -x "$project/../bin/python" ]; then python="$project/../bin/python" fi class_filter="s/^ *class +([A-Za-z0-9_]+Test)\(.*Test.*\):/\1/p" test_filter="s/^ *def +(test[a-zA-Z0-9_]+) *\(self.*$/\1/p" echo "<html><head>" echo "<title>Django test results</title>" echo "</head><body>" echo "<h1>Django test results</h1>" if [ -f "${project}/settings.py" -a \ -f "${project}/manage.py" ]; then echo "<h2>Test Results for: $app</h2>" echo "<pre>" # selected text test tests=$( if [ x"$TM_FILENAME" = x"tests.py" -a \ "$TM_SELECTED_TEXT" ]; then classname=$( sed -nE "1,${TM_INPUT_START_LINE}p" "${TM_FILEPATH}" |\ sed -nE "$class_filter" |\ tail -1 ) echo "$TM_SELECTED_TEXT" | while read l; do class_parse=$(echo "$l" | sed -nE "$class_filter") [ "$class_parse" ] && classname="$class_parse" test_parse=$(echo "$l" | sed -nE "$test_filter") [ "$test_parse" ] && echo "$app.$classname.$test_parse" done fi ) [ -z "$tests" ] && tests="$app" $python $project/manage.py test $tests # I don't have time to "fight" against wordpress # echo "CLOSE_pre_tag" else echo "<p style=\"color:red;\">Error: Django App expected.</p>" fi # Again, I don't have time to "fight" against wordpress # echo "CLOSE_body_tag CLOSE_html_tag""
- Este comando requer que o Bundle “Python Django” esteja instalado. Existe uma versão no repositório do próprio Textmate e uma versão atualizada no bitbucket.
- Acione “Bundles->Bundle Editor->Show Bundle Editor”.
- Selecione “Python Django” e clique no botão “+ New Command”.
- Escolha um nome para o comando. Aqui eu uso “Run App Tests”.
- Configure as opções do comando conforme abaixo:
- Save: All files in Project
- Commands: O script acima
- Input: None
- Output: Show as HTML
- Activation: Key Equivalent ⌃⌥⌘R
- Scope Selector: source.python.django
Modo de usar
- O comando é acionado com as teclas ⌃⌥⌘R.
- O comando executa apenas os testes da aplicação à qual o arquivo que você está editando pertence.
- Por padrão o comando executará todos os testes da aplicação.
- Se você selecionar o os testes que você quer executar no arquivo django_app/tests.py o comando executará apenas esses testes.
- O comando tem um suporte básico para usuários do virtualenv. Para que o comando use o virtualenv é necessário estruturar os seus diretórios da seguinte maneira: virtualenv_root/django_project/django_app. Isso é necessário para que o comando encontre o interpretador virtualenv_root/bin/python.


