Tag Python

Backup de e-mails com o NoPriv.py

19 de fevereiro de 2013, 01:23, por Renato Tags:

Através do podcast Linux Action Show, fiquei sabendo de um script em Python para backup de e-mails de contas IMAP que faz o download das mensagens e anexos e disponibiliza tudo em uma página HTML local.

O script se chama NoPriv.py e pode ser encontrado nesta página e neste repositório Github. A partir de uma conta de e-mail IMAP e uma lista de pastas a serem copiadas, ele cria uma estrutura de arquivos HTML para acesso às pastas como a deste exemplo. As cópias podem ser feitas de forma incremental, de modo que sejam transferidas apenas as novas mensagens em cada vez que o script for executado.

Para instalá-lo, basta clonar o repositório do Github e ajustar as configurações no arquivo nopriv.py:

###########################
# Do not edit above here  #
###########################

IMAPSERVER = "imap.gmail.com"
IMAPLOGIN = "janeway@gmail.com"
IMAPPASSWORD = "Voyager1"
IMAPFOLDER = ["[Gmail]/Sent Mail", "INBOX", "[Gmail]/Starred", "Captains_Log",
              "Important"]
ssl = True
incremental_backup = True

###########################
# Do not edit below here  #
###########################

A lista IMAPFOLDER deve conter as pastas que se deseja copiar. Vale notar que, para o caso do servidor do Gmail, as pastas padrão devem ser precedidas do prefixo [Gmail] enquanto que as pastas criadas pelo usuário não devem possuir este prefixo.

Para iniciar a cópia, basta executar:

python nopriv.py

Após o término, basta abrir o arquivo index.html e navegar pelas mensagens e anexos copiados. O arquivo também pode ser aberto em um navegador no terminal, como o Links2.

Strings com várias linhas em Python

05 de setembro de 2012, 21:00, por Renato Tags:

Recentemente, tive que preparar uma string com várias linhas, contendo o cabeçalho de um e-mail em um programa escrito em Python. Até aí, nenhuma novidade: bastava usar as três aspas para indicar o início e mais três para indicar o fim da string. No entanto, a string estava localizada em um bloco com indentação, o que fez com que a indentação ficasse incluída no conteúdo da string. Para entender melhor o que aconteceu, segue um exemplo:

def funcao():
    mensagem =  """From: admin@provedor.com.br
    To: destinatario@provedor.com.br
    Subject: Importante

    Aqui vai uma mensagem importante.
    """

    print mensagem

Chamando essa função no interpretador Python, vem o seguinte resultado:

>>> funcao()
From: admin@provedor.com.br
    To: destinatario@provedor.com.br
    Subject: Importante

    Aqui vai uma mensagem importante.

Como pode ser observado, da segunda linha em diante, a string acaba incluindo as indentações usadas no bloco de código.

O motivo desse comportamento é fácil de ser identificado, já que os espaços em branco estão de fato incluídos na string :-). No entanto, em alguns casos, como no caso de cabeçalhos de e-mail, é necessário que as strings não possuam caracteres em branco no início das linhas, caso contrário o cabeçalho não é interpretado corretamente pelos servidores de e-mail. Nesse caso, a forma mais fácil de corrigir o problema é remover os espaços iniciais da string:

def funcao():
    mensagem =  """From: admin@provedor.com.br
To: destinatario@provedor.com.br
Subject: Importante

Aqui vai uma mensagem importante.
"""

    print mensagem

Com essa alteração, o resultado esperado é obtido no teste com o interpretador:

>>> funcao()
From: admin@provedor.com.br
To: destinatario@provedor.com.br
Subject: Importante

Aqui vai uma mensagem importante.

No entanto, o código ficaria muito mais legível (e mais bonito :-P) se fosse possível resolver o problema mantendo a indentação da string. Para isso, pode-se usar a função dedent do módulo textwrap:

from textwrap import dedent

def funcao():
    mensagem =  dedent("""\
    From: admin@provedor.com.br
    To: destinatario@provedor.com.br
    Subject: Importante

    Aqui vai uma mensagem importante.
    """)

    print mensagem

A função dedent remove os caracteres de indentação comuns à todas as linhas de uma string. Nesse caso, como todas as linhas possuem quatro espaços iniciais, eles são removidos. Como o dedent só remove a indentação que é comum à todas as linhas, as linhas em branco também devem conter a indentação (como a linha 8). Além disso, vale notar que a primeira linha da string foi deslocada para baixo pare que todas as linhas ficassem com o mesmo espaço de indentação inicial. Com isso, a string acaba sendo iniciada por uma quebra de linha, o que geralmente não é desejado. Para contornar esse problema, foi incluída a barra inversa no início, que serve para fazer com que o caractere seguinte a ela seja ignorado (a quebra de linha).

Com isso, é obtido o resultado esperado:

>>> funcao()
From: admin@provedor.com.br
To: destinatario@provedor.com.br
Subject: Importante

Aqui vai uma mensagem importante.

Apesar do resultado ser o mesmo, acho que vale o trabalho de usar a função dedent para tornar o código mais legível. Para saber mais, veja a página de documentação do textwrap.

Python para aplicações científicas – Básico do básico

23 de setembro de 2011, 14:29, por Renato Tags:

Ultimamente, estive estudando algumas coisas sobre Python e tenho me interessado muito pela linguagem. Foi a primeira vez que tive contato com uma linguagem de tipagem dinâmica e logo de início, tive a impressão que ela seria uma ótima opção para substituir o Matlab. Gosto do Matlab, mas o fato de ser uma solução proprietária e não ser uma linguagem de propósito geral fazem com o Python tenha uns pontos a mais na minha classificação.

Para aplicações científicas, o Python conta com três bibliotecas fundamentais:

  • O NumPy, que é a biblioteca fundamental para aplicações científicas em Python. Ela oferece tipos especiais para representação de vetores e matrizes, além de outras ferramentas para álgebra linear e números aleatórios;
  • O SciPy, que é uma biblioteca que depende do NumPy e fornece rotinas para trabalhar em diversas áreas como integração numérica, otimização e processamento de sinais. Pode-se dizer que as rotinas do SciPy são análogas aos toolboxes do Matlab, guardadas as devidas proporções :-)
  • O matplotlib, que permite a criação de gráficos para visualização de dados.

Algumas funções do NumPy têm sintaxe parecida com a do Matlab, o que facilita as coisas para quem já é usuário do Matlab e esteja pensando em mudar para o Python. Por exemplo, para criar um vetor com 1000 elementos, de 0 a 1, espaçados linearmente, deve-se fazer:

import numpy as np
x = np.linspace(0, 1, 1000)

Nesse caso, x será um objeto do tipo array representando o vetor com 1000 elementos. Apesar de algumas semelhanças com o Matlab,  existem muitas diferenças na forma de se trabalhar com Python. Para criar um vetor com os elementos [1, 2, 3], por exemplo, deve-se fazer:

import numpy as np
x = np.array([1, 2, 3])

Para fazer referência aos itens do vetor, usam-se colchetes e o índice inicial é zero, ou seja, usa-se x[0] para retomar o primeiro item do vetor x.

Nesse, exemplo, além da sintaxe, existe uma outra diferença significante em relação ao Matlab: ao contrário do Matlab, que representa todas as matrizes e vetores com, no mínimo, 2 dimensões, o Python permite a criação de vetores unidimensionais. Assim, no exemplo anterior, uma chamada do tipo x[0,0] retornaria uma exceção ao contrário do que acontece no Matlab, que permite as chamadas x(1) ou x(1,1) para o primeiro elemento do vetor [1, 2, 3]. Entretanto, o Python também permite a criação de vetores de duas dimensões. O equivalente ao exemplo anterior, com duas dimensões, seria:

import numpy as np
x = np.array([[1, 2, 3]])

Vale notar que são usados dois colchetes, sendo o externo referente à definição da matriz (nesse caso, de 1 linha e 3 colunas) e o interno referente à definição da primeira linha da matriz. Nesse caso, x[0] retorna a primeira linha da matriz, ou seja, o vetor unidimensional [1, 2, 3]. Para retomar o primeiro item do vetor, devido à representação bidimensional, deve-se usar x[0,0]

Outra diferença significante é a sintaxe para multiplicação de matrizes. No Python, para multiplicar duas matrizes criadas como arrays, usa-se a função dot. Exemplo:

import numpy as np
# Matriz 2x2 A = [1 2
#                 3 4]
A = np.array([[1, 2], [3, 4])
# Matriz 2x2 B = [5 6
#                 7 8]
B = np.array([[5, 6], [7, 8])
# C = A*B
C = dot(A,B)

Já para fazer a multiplicação elemento por elemento, como feita com o operador .* no Matlab, usa-se apenas o asterisco no Python.

Existem ainda várias outras diferenças em relação ao Matlab. No endereço http://www.scipy.org/NumPy_for_Matlab_Users, estão descritas as mais importantes. Além disso, esse documento também é uma ótima referência para aprender as diferenças básicas entre o Matlab e o Python.

Em relação ao matplotlib, não cheguei a ver muita coisa, mas parece que a sintaxe é bem parecida com a do Matlab. Para inserir um gráfico de um período de senóide, por exemplo, deve-se fazer:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 1000)
y = np.sin(x)
plt.plot(x,y)
plt.show()

Por último, não posso esquecer de mencionar o iPython. Ele é um shell para Python com muitas melhorias em relação ao shell original. Ele oferece o recurso de auto-complete, e um acesso ao histórico de comandos, o que facilita muito o uso do shell. Além disso, em sua versão mais nova, ele veio cheio de novidades, conforme mostrado na SciPy 2011.

Para aprender sobre computação científica com Python, recomendo o site http://scipy-lectures.github.com/. Também vale a pena dar uma olhada nesses slides do Marcelo Caraciolo.