1. Instalando Python 3 na Dreamhost

    Quase um ano depois de instalar manualmente o python 2.7 e django na dreamhost, senti que era hora de tentar fazer o mesmo para o python 3.4.

    Hoje, o python padrão das instancias compartilhadas da Dreamhost já é o 2.7, tornando o post anterior desnecessário, mas já é hora de fazer o máximo de uso possível do python 3.

    Usei como base meu post anterior e este aqui Deploying Django with virtualenv on Dreamhost, que é bem direto e mais simples do que o que eu havia feito no passado, e pude seguir praticamente linha a linha para conseguir rodar uma aplicação com python 3 na dreamhost.

    Primeiro, é necessário fazer download e extrair o código fonte do python:

    1
    2
    3
    wget http://python.org/ftp/python/3.4.3/Python-3.4.3.tar.xz
    tar xvfJ Python-3.4.3.tar.xz 
    cd Python-3.4.3
    

    Depois disso, compilar e instalar o python (essa etapa vai demorar bastante, uma opção é fazer tudo dentro de uma screen):

    1
    2
    3
    ./configure --prefix=$HOME/python34
    make
    make install
    

    Depois de um bom tempo, as últimas linhas da instalação são especialmente interessantes:

    1
    2
    3
    4
    5
    6
    Collecting setuptools
    Collecting pip
    Installing collected packages: pip, setuptools
    
    
    Successfully installed pip-6.0.8 setuptools-12.0.5
    

    Ou seja, já temos o pip a nossa disposição, podemos checar que estamos usando a versão instalada no home do usuário.

    1
    2
    3
    4
    5
    6
    $ which python3
    /home/foo/python34/bin/python3
    $ which pip3
    /home/foo/python34/bin/pip3
    $ which pyvenv-3.4
    /home/foo/python34/bin/pyvenv-3.4
    

    Nesse ponto chegamos no momento mais específico da Dreamhost, que é o uso do passenger para aplicações python.

    Ele utiliza um arquivo passenger_wsgi.py na raiz do domínio que é usado para definir o python que será usado pela aplicação e outras informações, ele depende de uma variável “application” que é a aplicação wsgi que irá rodar.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    import sys, os
    import logging
    cwd = os.getcwd()
    sys.path.append(cwd)
    
    INTERP = os.path.expanduser("~/venv/bin/python")
    
    if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
    
    sys.path.insert(0,'$HOME/my_project/my_project')
    sys.path.insert(0,'$HOME/venv/bin')
    sys.path.insert(0,'$HOME/venv/lib/python3.4/site-packages/django')
    sys.path.insert(0,'$HOME/venv/lib/python3.4/site-packages')
    
    os.environ['DJANGO_SETTINGS_MODULE'] = "my_project.settings"
    from django.core.wsgi import get_wsgi_application
    application = get_wsgi_application()
    

    E pronto, bem mais simples que o caso do python 2.7 e pronto para trabalhar numa versão mais “evoluída” do python, mesmo que a hospedagem em si ainda não esteja.


  2. Um Djangonauta no Flask

    Quando saí do desenvolvimento com PHP fui diretamente para o Django, o ORM e admin foram suficientes para que convencer de que seria o framework ideal para mim, e venho usando ele em diversos projetos desde então.

    Porém me deparei com uma demanda de “criar uma página de contatos que envia um email”, e só, cheguei a começar a fazer o setup do projeto com o Django, mas a cada momento parecia mais que estava usando um canhão para matar uma formiga.

    Então resolvi fazer o projeto em Flask, havia feito apenas o tutorial alguns anos atrás mas parecia ser a opção correta para um projeto pequeno, um microframework para uma pequena demanda.

    Uma hora depois, 2 arquivos python (routes.py e forms.py), um template e alguns statics o problema estava resolvido.

    Além do flask, precisei instalar mais dois pacotes, Flask-Mail, Flask-WTF, o que foi bem tranquilo, já que ambos os pacotes tem uma boa documentação e são simples de usar, de certo modo, mais simples que o do Django.

    Um lado negativo que vejo é que para conseguir desenvolver essa pequena aplicação tive que manter 3 documentações diferentes abertas, e tive alguns problemas pra me acostumar com isso e as diferenças de como integrar as coisas, mas nada que um pouco de pratica não resolveria.


  3. Vantagens ao usar o runserver_plus

    O runserver_plus é um utilitário que pode te dar um pouco mais de produtividade quando desenvolvendo usando Django, faz parte do pacote django-extensions que tem vários outros comandos úteis para o desenvolvimento (como o shell_plus) e faz uso do Werkzeug, é simples instalá-lo via pip.

    1
    2
    pip install django-extensions
    pip install Werkzeug
    

    E adicioná-lo nas INSTALLED_APPS do django:

    1
    2
    3
    INSTALLED_APPS += (
            'django_extensions',
    ) 
    

    A partir daías telas d erro do Django ficaram assim:

    Traceback do runserver_plus

    A mais útil é um terminal python direto no traceback na tela, onde é possível fazer o debug do que causou a Exception, inspecionar as variáveis e o ambiente naquele momento e encontrar o problema.

    Terminal integrado

    Outra opção é ver o código fonte do arquivo onde aconteceu a Exception, talvez seu arquivo de view já esteja aberto no editor, mas como é possível visualizar isso do traceback inteiro, você pode ter mais informações do fonte do próprio Django

    Código Fonte

    E também é possível ver os comandos SQL gerados durante uma requisição passando o parametro “--print-sql” para o runserver_plus, que pode ser muito útil para visualizar o que o ORM do django está gerando, e encontrar locais onde o acesso ao banco pode estar gerando problemas.

    Código Fonte

    Essas são algumas vantagens que que o runserver_plus pode oferecer, são pequenos ganhos que ajudam na produtividade com Django.


  4. Problemas com pip freeze > requirements.txt

    Em muitos tutoriais é comum encontrar o comando pip freeze > requirements.txt como exemplo de como guardar os requisitos de um projeto.

    usar o requirements é uma boa prática e deve ser sempre seguida, porém o problema é quando ela é mal executada, podendo gerar mais problemas do que ajudar dependendo da situação.

    Por exemplo, tenho um projeto que usa o Markdoc para gerar uma wiki simples a partir de arquivos markdown, e tinha feito, a um bom tempo, o arquivo de requirements usando o pip freeze… gerando um arquivo assim:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    CherryPy==3.2.2
    Jinja2==2.6
    Markdoc==0.6.6
    Markdown==2.2.1
    PyYAML==3.10
    Pygments==1.5
    WebOb==1.2.3
    argparse==1.2.1
    wsgiref==0.1.2
    

    Onde todas as dependências do Markdoc foram parar no requirements, no momento tudo pareceu estar bem, porém, 2 anos depois, tentando regerar o virtualenv, me deparo com o erro a seguir:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    $ pip install -r requirements.txt
    Downloading/unpacking CherryPy==3.2.2 (from -r requirements.txt (line 1))
      Could not find a version that satisfies the requirement CherryPy==3.2.2 (from
      -r requirements.txt (line 1)) (from versions: 3.2.6, 3.4.0, 2.1.1, 2.2.0beta,
      3.2.3, 3.2.4, 3.2.4, 3.2.5, 3.2.5, 3.2.6, 3.2.6, 3.3.0, 3.3.0, 3.4.0, 3.4.0,
      3.5.0, 3.5.0, 3.6.0, 3.6.0)
        Some externally hosted files were ignored (use --allow-external to allow).
        Cleaning up...
        No distributions matching the version for CherryPy==3.2.2 (from -r
        requirements.txt (line 1))
        Storing debug log for failure in ~/.pip/pip.log
    

    Ou seja, a versão do CherryPy na época da criação do projeto não está mais disponível no PyPI, porém não é do CherryPy que eu preciso, e sim do Markdoc, então, ignorei o requirements e instalei o Markdoc diretamente.

    1
    $ pip install Markdoc
    

    E a instalação ocorreu normalmente, olhando o pip freeze, é possível notar que várias dependências do Markdoc foram atualizadas, mas o Markdoc em si continua na mesma versão:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    CherryPy==3.6.0
    Jinja2==2.7.3
    Markdoc==0.6.6
    Markdown==2.5.1
    MarkupSafe==0.23
    PyYAML==3.11
    Pygments==2.0.1
    WebOb==1.4
    argparse==1.2.1
    wsgiref==0.1.2
    

    Então, atualizei o requirements para ter apenas o Markdoc, o que vai evitar qualquer problema desse tipo no futuro.

    Como o projeto é muito simples foi fácil encontrar o problema e corrigir, mas se houvessem várias dependências ou dependências compartilhadas poderia ter sido bem mais complicado de se resolver.


  5. Instalando Python e Django na Dreamhost

    Os shared-hosts já foram a melhor opção de hospedagem barata e funcional que se tinha, porém a cada dia opções de VPS e de IaaS mais baratas aparecem, e os shared-hosts e suas limitações são deixados para trás.

    Um dos pontos negativos é a versão do python disponível, atualmente a dreamhost oferece a versão 2.6.6, o que obviamente não é o ideal, a última versão de cada ciclo (2.7 e 3.3) seria a melhor escolha.

    No meu caso, instalei a versão 2.7 que é a que estou usando em um projeto, aqui o passo a passo do que fiz, que poderia facilmente ser transformado em um bash script como já foi feito em alguns lugares, mas como eu só precisava do python, virtualenv e virtualenvwrapper, resolvi fazer manualmente.

    Para instalar o python:

    1
    2
    3
    4
    5
    wget http://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz --no-check-certificate
    tar xzvf Python-2.7.8.tgz
    cd Python-2.7.8
    ./configure --enable-shared --prefix=$HOME/opt/python-2.7.8
    make && make install
    

    O mais importante ali é a definição de um “prefix” no .configure, que permite instalar o python em uma pasta dentro do home do usuário.

    Depois, o virtualenv:

    1
    2
    3
    4
    5
    6
    7
    8
    mkdir opt/python-2.7.8/local
    wget https://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.9.1.tar.gz --no-check-certificate
    tar -xzf virtualenv-1.9.1.tar.gz
    cd virtualenv-1.9.1
    python virtualenv.py /home/user/opt/python-2.7.8/local/
    easy_install virtualenv
    source ~/opt/python-2.7.8/local/bin/activate
    easy_install virtualenv
    

    E finalmente o virtualenvwrapper:

    1
    2
    3
    4
    5
    6
    wget http://www.doughellmann.com/downloads/virtualenvwrapper-2.6.1.tar.gz --no-check-certificate
    tar -xzf virtualenvwrapper-2.6.1.tar.gz
    cd virtualenvwrapper-2.6.1
    python setup.py install
    cp virtualenvwrapper.sh ~/opt/python-2.7.8/
    mdkir ~/.virtualenvs
    

    Para que tudo isso funcione, é necessário complementar e adicionar algumas variáveis de ambiente e ativar o virtualenvwrapper, isso pode ser feito a partir do .profile ou do .bashrc

    .profile

    1
    2
    3
    4
    5
    export PATH=$HOME/opt/python-2.7.8/local/bin:$HOME/opt/python-2.7.8/bin:$PATH
    export PYTHONPATH=$HOME/opt/python-2.7.8/local/lib/python2.7/site-packages:$PYTHONPATH
    export LD_LIBRARY_PATH=$HOME/opt/python-2.7.8/lib/
    export WORKON_HOME=$HOME/.virtualenvs
    source $HOME/opt/python-2.7.8/virtualenvwrapper.sh
    

    Agora considerando um projeto usando Django, a dreamhost usa o passenger para executar aplicações em python, e um arquivo passenger_wsgi.py é necessário na raiz da pasta para a qual o domínio está apontando para fazer o passenger encontrar a aplicação.

    Essa deve ser provavelmente a parte mais complicada do processo, porque existe pouca ou nenhuma documentação de como é o modo correto de criar este arquivo.

    Os pontos importantes dele são:

    • Definir na variável INTERP o caminho para o executável do python a ser usável, de preferência sendo o do virtualenv criado para o projeto

    • Adicionar no path todos os caminhos pertinentes ao projeto, através do sys.path.insert, que atualiza o path adicionando novos valores no começo do mesmo.

    • Adicionar qualquer variável de ambiente necessária para o sistema no ambiente através do os.environ, no caso, estou setando o arquivo settings a ser usado pelo projeto.

    • A criação da variável “application” que vai ser usada pelo passenger para rodar a aplicação.

    passenger_wsgi.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    import sys, os
    
    # Switch to the virtualenv if we're not already there
    INTERP = os.path.expanduser("~/.virtualenvs/python/bin/python")
    if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
    
    PROJECT_ROOT = '/home/user/example'
    
    sys.path.insert(0, PROJECT_ROOT + '/example/')
    sys.path.insert(0, '/home/user/.virtualenvs/example/lib/python2.7/site-packages')
    os.environ['DJANGO_SETTINGS_MODULE'] = "example.settings.dreamhost"
    import django.core.handlers.wsgi
    application = django.core.handlers.wsgi.WSGIHandler()
    

    E por último, na dreamhost a pasta “public” deve ser usada para servir os arquivos estáticos da aplicação, nesse caso, é necessário definir o STATIC_ROOT e MEDIA_ROOT em pastas dentro do public, e os STATIC_URL e MEDIA_URL considerando o caminho a partir da public.

    settings/dreamhost.py

    1
    2
    3
    4
    5
    6
    7
    STATIC_ROOT = os.path.join(HOME_DIR, 'example.daniloshiga.com', 'public', 'static')
    
    STATIC_URL = '/static/'
    
    MEDIA_ROOT = os.path.join(HOME_DIR, 'example.daniloshiga.com', 'public', 'media')
    
    MEDIA_URL = '/media/'
    

    Do modo que está acima, essas pastas vão ficar em /home/user/example/example.daniloshiga.com/public/static e /public/media, mas a URL delas é apenas /static e /media.

    Depois disso, para reiniciar o passenger toda vez que houver uma novidade no projeto, é necessário alterar a data de modificação de um arquivo restart.txt dentro da pasta tmp/ do domínio, por exemplo, através do comando:

    1
    touch ~/example.daniloshiga.com/tmp/restart.txt
    

    Se isso não for suficiente, ainda é possível matar os processor do python que estiverem rodando, usando o comando pkil python.

    E é isso, foi um processo um pouco trabalhoso, mas tem a vantagem de dar mais liberdade em um ambiente limitado, o que permite aproveitar algumas vantagens de uma hospedagem como a dreamhost


  6. Introdução aos Testes no Django

    Estou iniciando no processo de gerar testes para meu código no django, vou ir colocando as minhas impressões sobre o assunto.

    Em primeiro lugar, pelo menos na versão 1.5, é de senso comum que o código de testes apresentado para o Django está longe do ideal, o que vejo é que a maioria dos projetos não faz uso do “tests.py” padrão gerado no comando “createapp”, logo existem muitas versões diferentes de estruturas e testrunners na internet.

    Decidi me basear no que pode ser encontrado no Two Scoops of Django.

    Um detalhe importante é verificar qual versão do Django está sendo usada, porque da 1.5 para a 1.6 houve uma troca no “test runner” para usar um que encontra com mais facilidade os testes dentro dos módulos.

    Nesse caso, é interessante criar um settings/test.py específico para testes. De modo que seja usado um banco de dados sqlite na memória, que torna o processo bem mais rápido. o settings pra versão 1.5 e 1.6 podem ser encontrados no github do projeto base do Two Scoops of Django.

    A partir daí, é apenas começar a escrever os testes :), o que preciso começar a fazer e aprender conforme faço.


  7. Pelican

    É isso aí, wordpress é legal, tem um painel administrativo e tudo mais, mas está na hora de ser um dos caras legais, resolvi trocar o wordpress por um gerador de sites estático, e entre vários, escolhi o Pelican.

    Pra mim, a grande vantagem é o tempo de carregamento, sem a necessidade de processamento e acesso ao banco, o blog ficou bem mais rápido.

    A grande maioria dos meus posts aqui acabaram sendo sobre o próprio blog, técnicas mirabolantes para manter o wordpress atualizado e plugins bizarros para conseguir postar usando o vim (bizarro mas legal).

    Queria um tema simples, o mais minimalista possível, principalmente porque não sou muito bom na parte de design. Então montei o layout usando o Toast, um framework CSS bem simples, que o próprio autor considera como apenas framework para facilitar a criação de wireframes, mas que eu gostei muito da simplicidade, sem a necessidade de colocar algo enorme como um bootstrap (o código do Toast tem apenas algumas regras bem simples.).

    Para atingir essa simplicidade o mesmo não funciona no IE7, mas tudo bem, não espero que ninguém acessando isso daqui esteja usando ele.

    Considerei em colocar os comentários do Google Plus, gosto do modo como eles se misturam com as postagens na rede social (de forma muito melhor do que a do facebook, por exemplo), mas por padrão o widget do Google não é responsivo, além de ser necessário ter conta para comentar.

    E como o Pelican já tinha tudo pronto para uso do Disqus, resolvi utilizá-lo, tinha trauma do mesmo pela lentidão que apresentava anos atrás, mas isso parece ter se resolvido.

    Outra coisa que aproveitei para fazer foi adicionar as tags semânticas do schema.org, agora os posts tem definido corretamente autor, conteúdo e data de postagem, o que já é um bom começo e que o Google já entende do que se trata na hora de indexar.

    Então é isso, não cheguei a fazer uma comparação muito exata, mas tenho certeza que o blog está por volta de 3 vezes mais rápido para carregar, e aguentando uma quantidade muito maior de visitas sem problemas, agora é fazer mais postagens, se possível sem ser apenas sobre o próprio blog.

Página 1 / 1