Problemas com o postgresql após upgrade para o Ubuntu Karmic

Novembro 6, 2009 Rico Deixe um comentário

Para quem fez o upgrade do Ubuntu para o Karmic Koala e teve problemas com o PostgreSQL aqui vai a dica.

Na nova versão do Ubuntu, o PostgreSQL 8.3 foi substituído pelo 8.4, mas (pelo menos para mim) as bases não foram copiadas ou convertidas. Sem a versão anterior rodando, eu não pude fazer um dump para importar para a nova.

Para resolver o problema, o melhor a se fazer é remover a nova versão do PostgreSQL e restaurar a versão antiga. Ao fazer o upgrade de sistema, os arquivos de configuração são mantidos (em /etc/postgresql/8.3/main), então é bem provável que tudo funcione como estava antes da atualização.

sudo apt-get remove postgresql-8.4 postgresql-client-8.4
sudo apt-get install postgresql-8.3 postgresql-client-8.3

Com o PostgreSQL voltando a funcionar você pode optar por manter a versão antiga, ou fazer um backup e restaurar na nova versão (aconselhável).

Categoriastech Tags:, , ,

Auto-completar com o Fabric

Outubro 28, 2009 Rico Deixe um comentário

Estive fazendo algumas coisas com fabric e senti falta de um auto-completar para as tarefas disponíveis.

Aí descobri que era possível listar as tarefas usando:

fab --list

Dei uma olhada no autocomplete do Django e também encontrei este artigo que me ajudou bastante.

Juntando um pouco daqui e dali cheguei neste script que deixei junto das minhas dotfiles.

Parece coisa de preguiçoso, normalmente as tarefas têm pouco mais de 4 letras, mas tudo bem, ajudar não dói não é?

Para instalar é só chamar o script no seu .bashrc ou .bashprofile:

. /caminho/para/fab_bash_completion

Também serve de exemplo para fazer o auto-completar dos seus próprios comandos.

Apache, processos, threads e django

Setembro 29, 2009 Rico 2 comentários

Muitas vezes apenas adotamos os padrões e não nos questionamos porque eles foram escolhidos, então resolvi fazer uma breve pesquisa sobre threads e processos no Apache

Antes de mais nada, é importante falar um pouco sobre processos e threads. Os processos são independentes e têm seus próprios endereços de memória, os threads pertencem a um processo e compartilham o mesmo endereço de memória e recursos.

Tudo começa no webserver, vou falar do Apache. Existem dois sabores que se diferenciam em como será feito o processamento de múltiplas requisições: prefork e worker.

O prefork tem um processo de controle para outros sub-processos que irão receber e responder às requisições. Aqui não são utilizados threads, uma requisição é repassada para o primeiro sub-processo livre e este, por sua vez, só atenderá a uma requisição por vez.

O worker também tem um processo de controle para outros sub-processos, a diferença é que cada sub-processo cria um thread de escuta que fará o repasse de requisições para outros threads. Isto faz com que o uso de memória normalmente seja menor, pois os threads compartilham os mesmos recursos.

Em ambos os modelos é possível regular o mínimo ou máximo de processos e threads, o Apache se encarrega de reciclar os processos dentro destes limites. O ideal é que o servidor esteja configurado para aguentar o número esperado de requisições mas evitando consumir toda a RAM disponível, o que resultaria em uso da SWAP em disco e uma cascata de problemas.

Segundo a documentação, o prefork é indicado para evitar threading em aplicações que utilizam bibliotecas non-thread-safe, ou seja, evitar que ações em threads diferentes de um mesmo processo possam influenciar outro thread. Como o worker mantém um conjunto de threads em um mesmo processo, compartilhando recursos, bibliotecas mal preparadas podem causar resultados inesperados.

Em geral, o Django é tido como thread-safe, houve uma discussão sobre isso mas acredito que muitos dos problemas da época já tenham sido resolvidos. Ainda não fiz a experiência, mas este post do Armin Ronacher compara o sistema de templates do Django com o Jinja e comenta que algumas templatetags como a cycle não são thread-safe.

Por muito tempo o Django teve o modpython com Apache prefork como deploy recomendado, agora a recomendação oficial é para se utilizar o modwsgi* mas não cobre qual modelo de webserver é mais adequado.

* Curiosidade: conversando com o Jacob na Python Brasil aprendi que se pronuncia “mód uísgui”, mais fácil não? :)

Aqui vão mais alguns links interessantes:

Categoriasdjango, tech Tags:, , ,

Conversor Python de Extratos da Caixa Econômica para o Moneylog

Agosto 17, 2009 Rico Deixe um comentário

Não tenho mantido muito controle das minhas contas mas resolvi tentar me organizar.

O Aurélio lançou a nova versão do Moneylog e eu resolvi testar. Estou achando muito interessante.

O esquema de tags é ótimo para ver gastos específicos. Tem busca, expressões regulares, relatórios. O falecido Microsoft Money deve estar com vergonha.

Para facilitar as coisas, escrevi um conversor de extratos da Caixa Econômica e resolvi publicar, pois pode ser útil para mais alguém.

Por simplicidade, a saída vai para o console, então é só direcionar para um arquivo de saída:

python caixalog.py caixa-2009.02-txt > moneylog-2009-02.txt

Vou passar o arquivo para o Aurélio. Se for útil para você, ou se tiver alguma sugestão, deixe um comentário aqui!

Como o WordPress não permite a publicação de arquivos que não sejam de vídeo, imagem ou som, vou colocar o código aqui mesmo. Para usar é preciso colar em um arquivo “caixalog.py” e ter o python instalado.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
caixalog.py
===========

Conversor de extratos em texto da Caixa Econômica para o formato do
moneylog (http://aurelio.net/moneylog).

Autor: Enrico Batista da Luz
Blog: http://ricobl.wordpress.com/
Criado: 2009-08-15

Exemplo de formato de entrada exportado do site da Caixa:

    "Conta";"Data_Mov";"Nr_Doc";"Historico";"Valor";"Deb_Cred"
    "0000000000000000";"20090105";"000000";"CP MAESTRO";"15.00";"D"

Uso:

    python caixalog.py arq1.txt [arq2.txt, arq3.txt] > arq_saida.txt

Exemplos:

    # Saída no console
    python caixalog.py extrato-2009-fev.txt
    # Um arquivo apenas
    python caixalog.py extrato-2009-fev.txt > moneylog-2009-fev.txt
    # Vários arquivos
    python caixalog.py extrato-2009-*.txt > moneylog-2009.txt

* ATENÇÃO:

    O segundo e terceiro comandos acima irão substituir os arquivos
    de saída, é recomendável fazer um backup dos seus arquivos antes
    de rodar o script.
"""

import csv
import os
import sys

# Formato das linhas para o arquivo de saída:
# DATASINALVALORTAGS E DESCRIÇÃO
output_format = '%(Data_Mov)s\t%(Deb_Cred)s%(Valor)s\t%(Historico)s'

# Mapeamento de descrição para tags padrão
tag_map = {
    'PAG BLOQTO': 'boleto',
    'CP MAESTRO': 'debito',
    'CVPREV': 'previd,invest',
    'PAG FONE': 'cel,boleto',
    'SAQ LOTER': 'saque,lot',
    'CAIXA24H': 'saque,atm',
    'TRX CT INV': 'invest',
    'CP PREPAGO': 'cel,recarga',
    'SAQ CARTAO': 'saque,caixa',
}

def add_tags(desc):
    """
    Adiciona tags à descrição se houver um mapeamento.
    """
    tags = tag_map.get(desc, None)
    if tags:
        return '%s | %s' % (tags, desc)
    return desc

def format_date(d):
    """
    Converte a data no formato yyyymmdd para yyyy-mm-dd.
    """
    return '-'.join((d[:4], d[4:6], d[6:]))

def process_file(file_path):
    """
    Processa um extrato da Caixa e converte para o formato do Moneylog.
    """
    # Verifica se o arquivo existe
    if not os.path.isfile(file_path):
        raise SystemExit('Arquivo %s não encontrado!' % file_path)

    # Abre o arquivo para leitura e cria o leitor de CSV
    input = open(input_file, 'rb')
    reader = csv.reader(input, delimiter=';')
    # Lê a primeira linha com os nomes das colunas
    headers = reader.next()
    # Processa cada linha, criando um dicionário dos valores
    # de acordo com as nomes das colunas
    for row in reader:
        # Cria o dicionário
        data = dict(zip(headers, row))
        # Formata a data
        data['Data_Mov'] = format_date(data['Data_Mov'])
        # Ajusta o sinal (vazio para crédito ou '-' para débito)
        data['Deb_Cred'] = (data['Deb_Cred'] == 'D') and '-' or ''
        # Troca pontos por vírgulas no valor
        data['Valor'] = data['Valor'].replace('.', ',')
        # Adiciona tags ao histórico
        data['Historico'] = add_tags(data['Historico'])

        # Imprime a linha formatada
        print output_format % data

    # Fecha o arquivo de entrada
    input.close()

if __name__ == '__main__':
    # Captura os parâmetros da linha de comando.
    # O primeiro é o próprio script, os seguintes
    # são os arquivos a serem processados.
    input_files = sys.argv[1:]

    # Verifica se algum arquivo foi passado
    if len(input_files) < 1:
        raise SystemExit('Parâmetros inválidos')

    # Processa cada arquivo
    for input_file in input_files:
        process_file(input_file)

Manager para diferentes conexões de banco no Django

Agosto 6, 2009 Rico 10 comentários

Pra tirar um pouco as teias de aranha do blog, vou escrever sobre algo que fiz recentemente e achei bacana.

Eu estava trabalhando em um novo projeto (em Django, é claro), vinculado a um projeto principal e comecei a me sentir um pouco amarrado. Os dois projetos compartilhavam as mesmas aplicações mas depois de algumas definições no meio do caminho pode-se ver que eles precisariam compartilhar pouquíssimo conteúdo.

Há algum tempo, havia visto um manager que era capaz de se conectar a um banco diferente do padrão e achei que esta seria a solução ideal. Eu poderia separar o conteúdo dos dois projetos e, quando precisasse, usaria o banco de dados do outro projeto.

O manager que eu havia visto estava em algum destes projetos em Django que foram abertos ao público recentemente, mas não consegui mais encontrar. Então me vi obrigado a fazer um pouco de pesquisa e inventar o meu próprio.

Acabei encontrando uma solução do Eric Florenzano e outra do Kenneth Falck.

A do Erick parecia um tanto antiga e junto com a pesquisa esbarrei na changeset 10026, em que foi alterada a maneira de se conectar ao banco, ao invés de usar o módulo django.conf.settings o parâmetro passa a ser um dicionário com dados de conexão, e isso facilitou bastante.

Chega de papo furado e vamos ao código. Vou explicando por partes.

Primeiro foi preciso definir uma maneira fácil de usar conexões diferentes sem ficar repetindo no código as configurações de cada conexão. A solução copiada do Eric foi criar um dicionário de conexões nas configurações do projeto:

# Configurações padrão do banco
DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = 'default_db_name'
DATABASE_USER = 'user'
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''

# Configuração padrão + alternativas
DATABASES = {
    'default': {},
    'alternative': {
        'DATABASE_NAME': 'alternative_db_name',
    },
}

Como eu disse, quiz deixar fácil o uso de conexões diferentes, então fiz com que não fosse necessário repetir os dados de configuração de cada conexão, visto que é comum que se use o mesmo usuário, senha, engine, etc. Então se você pretende somente usar outro banco, basta mudar o DATABASE_NAME. Abaixo o código responsável por isto:

from django.conf import settings
from django.db import models, backend

# Dicionário de conexão padrão
db_settings = {
    'DATABASE_HOST': settings.DATABASE_HOST,
    'DATABASE_NAME': settings.DATABASE_NAME,
    'DATABASE_OPTIONS': settings.DATABASE_OPTIONS,
    'DATABASE_PASSWORD': settings.DATABASE_PASSWORD,
    'DATABASE_PORT': settings.DATABASE_PORT,
    'DATABASE_USER': settings.DATABASE_USER,
    'TIME_ZONE': settings.TIME_ZONE,
}

def prepare_db_settings(db_profile_name):
    """
    Recebe um dicionário de conexão alternativa e retorna um novo dicionário,
    completando propriedades ausentes com os valores padrão.
    """
    return dict(db_settings, **settings.DATABASES[db_profile_name])

Por fim, o manager se comporta normalmente, se você quiser conectar a um banco diferente é só usar o método use, informando o nome do perfil de conexão que deseja utilizar. O manager retorna a query padrão mas aponta para outro banco de dados. Bacana não?

class MultiDBManager(models.Manager):
    """
    A manager that can connect to different databases.
    """
    def use(self, db_profile_name):
    	"""
    	Return a queryset connected to a custom database.
    	"""
        # Get customized database settings to use in a new connection wrapper
        db_settings = prepare_db_settings(db_profile_name)

    	# Get the queryset and replace its connection
        qs = self.get_query_set()
        qs.query.connection = backend.DatabaseWrapper(db_settings)
        return qs

Mas nem tudo são flores, é tudo muito experimental e não foi testado a fundo. Aqui vão alguns problemas conhecidos:

  1. Você vai encontrar erros se tentar acessar models relacionados, o manager inicial vai usar a conexão alternativa, mas o model relacionado vai ser procurado no banco padrão. Para contornar isto use o método select_related(‘model_relacionado’), desta forma todos os models serão listados em apenas uma consulta ao mesmo banco.
  2. Não foi testado nenhum tipo de alteração de dados (inclusão, edição, exclusão). O post do Eric talvez possa ajudar a encontrar uma solução neste sentido.

De qualquer forma, tem sido bastante útil para integrar projetos sem fazer muita bagunça.

E você? O que achou? Deixe sua opinião nos comentários!

* Disponibilizei o código no Django Snippets também: Manager for multiple database connections.

Fim do Firefox está próximo?

Junho 26, 2009 Rico 2 comentários

Sempre fui um grande fã do Firefox. É um browser rápido e seguro para o usuário comum e um ótimo browser para quem trabalha com desenvolvimento web.

Com o lançamento do Chrome, o Firefox parou de ser distribuído como browser padrão nos pacotes de software do Google e com isso teve seu orçamento prejudicado, que é sustendado em grande parte pelo Google.

De lá pra cá, os releases do Firefox têm sido cada vez mais demorados. Houve uma confusão com o lançamento da versão 3.1 sendo alterada para 3.5, pulando uma versão mas agregando mais recursos. Pode ter sido uma jogada de marketing, uma tentativa de ganhar tempo, não sei, só sei que já perdi as contas de quantas vezes os lançamentos foram adiados.

A flexibilidade do Firefox é ótima, é um grande exemplo de um software modular com os seus complementos, temas e configurações avançadas. Em relação aos IEs, ainda é um browser leve, mas se compararmos ao Chrome, é um monstro comedor de memória.

Como prova, é só reparar no marketing que a Mozilla está fazendo para a nova versão do seu browser: “30% mais veloz que a versão anterior”, isso porque eles não podem dizer que é mais veloz que o Chrome, Safari, Opera, ou até o novo IE 8.

O Chrome tem um baixíssimo consumo de memória, sua arquitetura baseada em processos o torna mais seguro e estável, sem falar que é mais rápido para executar scripts e renderizar páginas, o que facilita a utilização de aplicativos web.

Por isso tenho a impressão de que o Firefox não terá uma longa vida se não começar a evoluir mais rápido. O Chrome já tem um suporte primário a customização através de user scripts e extensões, mas a instalação destes complementos ainda não é prática, o processo ainda é muito manual e não há um canal de distribuição.

Até onde eu sei eles estão trabalhando para melhorar isto, algo que não deve demorar muito, e quando começar imagino que o Chrome comece a ganhar cada vez mais espaço. Um ponto interessante é a idéia de fazer com que os complementos possam ser instalados sem que o browser seja reiniciado.

Vale lembrar também que versões do Chrome para Mac e Linux estão no forno, já existem versões instáveis e não deve demorar muito para que se estabilizem.

Alguns projetos experimentais da Mozilla também parecem desperdício de tempo. O primeiro exemplo disso é o Personas, algo um pouco mais avançado que os temas que já existem, mas sem muito mais graça. Gostaria de ver mais esforços no browser do que neste tipo de projeto.

Não vou me admirar se a comunidade open source que se dedica ao Firefox começar a migrar para o Chromium. Imagino que seja mais fácil deixar o Chromium flexível do que deixar o Firefox leve.

Categoriastech Tags:, , , ,

Ganhei o Livro de Expressões Regulares do Aurelio – Parte II

Maio 18, 2009 Rico Deixe um comentário

Há alguns dias contei como ganhei o Livro de Expressões Regulares do Aurélio.

Para provar que a promoção não foi balela, semana passada ele esteve aqui em Curitiba para organizar a sua mudança e marcamos a entrega do livro. Como temos alguns amigos em comum, aproveitamos para juntar mais um pessoal e jogar um pouco de conversa fora.

Comecei a ler o livro, como de costume é uma abordagem muito bacana, simples e divertida. Tenho certeza de que vai me ajudar a entender alguns detalhes mais sórdidos das expressões regulares que ainda não entraram na minha cabeça.

Aproveito para agradecer ao Aurélio pelo livro e para desejar boa sorte nessa nova jornada em Joinville.

Categoriasmisc Tags:, , ,

Version GCC_4.2.0 not found (required by /usr/lib/libstdc++.so.6)

Maio 13, 2009 Rico Deixe um comentário

Atualização de kernel no Ubuntu costuma causar problemas em módulos que não foram instalados pelo gerenciador de pacotes.

Ainda estou usando o Ubuntu 8.04, quero atualizar para o 9.04 assim que tiver um tempinho sobrando.

Assim que fiz a última atualização, meu VMWare e placa de vídeo pararam de funcionar. Por hábito, já deixo os arquivos de instalação guardados para reinstalar quando precisar.

Ao tentar rodar o VMWare, aparece o seguinte erro:

/usr/lib/vmware/bin/vmware: /usr/lib/vmware/lib/libgcc_s.so.1/libgcc_s.so.1: version `GCC_3.4' not found (required by /usr/lib/libcairo.so.2)
/usr/lib/vmware/bin/vmware: /usr/lib/vmware/lib/libgcc_s.so.1/libgcc_s.so.1: version `GCC_4.2.0' not found (required by /usr/lib/libstdc++.so.6)
/usr/lib/vmware/bin/vmware: /usr/lib/vmware/lib/libgcc_s.so.1/libgcc_s.so.1: version `GCC_3.4' not found (required by /usr/lib/libcairo.so.2)
/usr/lib/vmware/bin/vmware: /usr/lib/vmware/lib/libgcc_s.so.1/libgcc_s.so.1: version `GCC_4.2.0' not found (required by /usr/lib/libstdc++.so.6)
/usr/lib/vmware/bin/vmware: /usr/lib/vmware/lib/libgcc_s.so.1/libgcc_s.so.1: version `GCC_3.4' not found (required by /usr/lib/libcairo.so.2)
/usr/lib/vmware/bin/vmware: /usr/lib/vmware/lib/libgcc_s.so.1/libgcc_s.so.1: version `GCC_4.2.0' not found (required by /usr/lib/libstdc++.so.6)

Pesquisando achei este post, dizendo para tirar do caminho o módulo problemático libgcc_s.so.1/libgcc_s.so.1 em /usr/lib/vmware/bin/vmware.

cd /usr/lib/vmware/lib
sudo mkdir bak
sudo mv libgcc_s.so.1/libgcc_s.so.1 bak/

Agora tudo funciona como antes.

Categoriastech Tags:, , , ,

Django UnicodeEncodeError com upload usando WSGI

Maio 13, 2009 Rico 2 comentários

Se você se deparou com um UnicodeEncodeError ao fazer o upload de algum arquivo com caracteres especiais usando WSGI no Django, a solução pode estar aqui: How to use django with mod_wsgi – Additional Tweaking.

Eu passei pelo seguinte erro:

UnicodeEncodeError: 'ascii' codec can't encode characters
in position 86-87: ordinal not in range(128)

Em resumo é preciso alterar as variáveis de ambiente LANG e LC_ALL do Apache:

export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

Isto é feito alterando o arquivo envvars do Apache, normalmente em /etc/apache2/envvars.

Em algumas instalações / distribuições, este arquivo pode não existir ou não estar sendo chamado no httpd.conf, neste caso é preciso configurar manualmente.

No FreeBSD é preciso criar um arquivo com a extensão .env em /usr/local/etc/apache2/envvars.d. Como isto é ligado ao WSGI, chamei de mod_wsgi.env.

Depois de alterar é preciso reiniciar o apache.

Agora uploads de arquivos nomeados com caracteres especiais funcionam normalmente.

Categoriasdjango, tech Tags:, , ,

Ganhei o Livro de Expressões Regulares do Aurelio

Maio 6, 2009 Rico 10 comentários

O Aurélio vendeu 1000 exemplares da segunda edição do seu livro Expressões Regulares – Uma Abordagem Divertida e para comemorar lançou uma promoção que daria uma cópia para quem acertasse o número de exemplares vendidos em Abril de 2009.

Resolvi participar e desta vez usei a cabeça.

Procurei no blog pela data de lançamento do livro, achei o post de 15 de Agosto de 2008, até o dia que o Aurélio anunciou a venda de 1000 unidades, 29 de Abril, são uns 9 meses.

É uma média de 111 exemplares vendidos por mês. Imagino que tenha vendido mais no começo, por ser novidade e toda a propaganda inicial. Depois deve ter estabilizado ou sofrido uma queda suave.

Calculei que deveria estar entre uns 80 a 95 exemplares, pesquisei o número que as outras pessoas estavam chutando para garantir que o meu palpite fosse único. E resolvi chutar 87, logo depois chutaram 88, quaaaase perco.

Hoje o Aurélio anunciou que eu ganhei!!! Aloco! Nunca ganho nada em bingo, rifa, etc. Dei sorte.

Então logo devo ganhar o livro, já tenho o que ele escreveu sobre Shell e recomendo, o Aurélio tem uma linha de escrita divertida e simplificada.

Valeu Aurélio!!!

UPDATE 18/05/2009: o livro já está em mãos com dedicatória e tudo! :)

Categoriasmisc Tags:, , ,