Um guia para pacotes Python

Republicado de imasters.com.br

Um guia para pacotes Python

O principal para um projeto de software livre de sucesso é o pacote. Um ingrediente chave para um bom pacote é a versão. Como o projeto é de software livre, o ideal é publicar o pacote para aproveitar os muitos benefícios que a comunidade de software livre oferece.

Diferentes plataformas e linguagens têm mecanismos diversos para pacotes, mas este artigo se concentra especificamente em Python e seu ecossistema de pacotes. O artigo discute mecânica de pacotes para oferecer uma base e fornece exemplos práticos suficientes para que o leitor comece imediatamente.

Por que se preocupar com pacotes?

Além de ser a coisa certa a se fazer, há três motivos práticos para empacotar software:

  • Facilidade de uso
  • Estabilidade (com versões)
  • Distribuição

Tornar a instalação do aplicativo o mais simples possível é uma questão de consideração para com os usuários. Pacotes tornam o software mais acessível e mais fácil de instalar. Se for mais fácil de instalar, será mais fácil para que usuários comecem a usar o software.

Ao publicar um pacote no Python Package Index (PyPI), ele poderá ser facilmente acessado por meio de utilitários como pip oueasy_install.

Além disso, ao criar versões de pacotes, o desenvolvedor permite que os usuários “fixem” a dependência que seus projetos têm em relação ao software a uma versão em particular. Por exemplo, fixar Pinax para a versão 0.9a2.dev1017 seria expresso como:

Pinax==0.9a2.dev1017

Isso forçaria o projeto a usar o release 0.9a2.dev1017 do Pinax.

Versões garantem maior estabilidade caso sejam lançadas alterações de releases para seu software mais tarde que possam ter quebra de interfaces. Permitem aos usuários saber exatamente o que estão obtendo e facilitam para eles acompanhar as diferenças em releases.

Além disso, os desenvolvedores de projeto podem saber exatamente para o que estão criando código.

Um método comum para publicar pacotes no PyPI (ou em um servidor de distribuição próprio) é criar uma distribuição de origem para upload. Uma distribuição de origem é uma maneira padrão de empacotar a origem de seu projeto como uma unidade distribuível.

Há maneiras de criar distribuições binárias, mas, para o software livre, faz sentido também distribuir a origem.

Criar distribuições de origem facilita o uso de ferramentas que procuram o software na Internet, fazem download e instalam automaticamente. Esse processo ajuda não só no desenvolvimento local, mas também nas implementações do software.

Portanto, ao tornar mais fácil para usuários integrar e instalar o software, usar boas versões que permitem uma técnica confiável de fixação e publicar o pacote para distribuição mais ampla, você terá uma chance maior de que seu projeto tenha sucesso e obtenha aprovação ampla. Aprovação ampla pode levar a mais contribuidores — algo que certamente todo desenvolvedor de software livre deseja.

Anatomia de um arquivo setup.py

Um dos propósitos do script setup.py é servir como o executável que pode ser executado para empacotar o software e fazer upload para servidores de distribuição. O script setup.py pode variar bastante em conteúdo conforme você navega pelos repositórios Python populares. Este artigo se concentra no básico.

O arquivo setup.py pode ser usado para muitas tarefas diferentes, mas aqui você cria um que permitirá executar os seguintes comandos:

python setup.py register
python setup.py sdist upload

O primeiro comando, register, toma as informações fornecidas na função setup() no script setup.py e cria uma entrada no PyPI para seu pacote. Ele não faz upload; em vez disso, cria os metadados sobre o seu projeto, de modo que posteriormente seja possível fazer upload e hospedar os releases lá.

Os próximos dois comandos estão encadeados: sdist upload desenvolve uma distribuição de origem e faz upload dela para o PyPI. Mas há alguns pré-requisitos, como configurar seu próprio arquivo de configuração .pypirc e escrever efetivamente o conteúdo de setup.py.

Primeiro, configure o arquivo .pypirc. Ele deve estar em seu diretório inicial, que varia dependendo do sistema operacional. No UNIX®, Linux® e Mac OS X, chega-se lá digitando cd ~/. O conteúdo do arquivo deve conter suas credenciais PyPI, como mostrado abaixo:

[distutils]
index-servers =
pypi

[pypi]
username:xxxxxxxxxxxxx
password:xxxxxxxxxxxxx

 Em seguida, acesse o PyPI e registre uma conta (não se preocupe, é grátis). Coloque o mesmo nome de usuário e senha criados no PyPI em seu arquivo .pypirc e nomeie o arquivo ~/.pypirc.

Agora, ao criar o script setup.py, é preciso decidir o que será exibido na página de índice do PyPI e qual será o nome do projeto. Comece copiando um modelo de setup.py que eu uso para projetos (consulte a listagem abaixo).

Ignorando as importações e funções, olhe para a parte inferior do modelo, para o que precisa ser mudado para se adequar ao seu projeto.

PACKAGE = ""
NAME = ""
DESCRIPTION = ""
AUTHOR = ""
AUTHOR_EMAIL = ""
URL = ""
VERSION = __import__(PACKAGE).__version__

setup(
name=NAME,
version=VERSION,
description=DESCRIPTION,
long_description=read("README.rst"),
author=AUTHOR,
author_email=AUTHOR_EMAIL,
license="BSD",
url=URL,
packages=find_packages(exclude=["tests.*", "tests"]),
package_data=find_package_data(
PACKAGE,
only_in_packages=False
),
classifiers=[
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Framework :: Django",
],
zip_safe=False,
)

Primeiro, observe que este modelo espera que o projeto tenha dois arquivos diferentes. O primeiro é usado para long_description: ele lê o conteúdo do arquivo README.rst que está no mesmo diretório que setup.py e passa o conteúdo como uma cadeia de caracteres para o parâmetro long_description.

Esse arquivo preenche a página de entrada no PyPI, portanto é bom descrever brevemente o projeto e mostrar exemplos de uso nesse arquivo. O segundo arquivo é __init__.py . Ele não é mencionado explicitamente aqui, mas a linha que define a variável VERSION importa o pacote; e quando isso acontece, Python precisa de um arquivo __init__.py e espera uma variável definida naquele módulo, chamada __version__.

Por enquanto, basta defini-la como uma cadeia de caractere:

# __init__.py
__version__ = "0.1"

Agora vamos ver as demais entradas:

  • Package é o pacote Python no projeto. É a pasta de nível superior que contém o módulo __init__.py que deve estar no mesmo diretório que o arquivo setup.py — por exemplo:
/-
|- README.rst
|- setup.py
|- dogs
|- __init__.py
|- catcher.py

Portanto,

dogs

seria o pacote aqui.

  • Name é geralmente o mesmo que Package ou semelhante, mas pode ser qualquer coisa. Name é como as pessoas chamarão o software, o nome pelo qual ele será listado no PyPI e — o mais importante — sob o qual os usuários irão instalá-lo (por exemplo, pip install NAME).
  • Description é apenas uma breve descrição do projeto. Uma frase é o bastante.
  • Author e Author_Email são o que parecem: o nome e endereço de e-mail do autor. Essas informações são opcionais, mas é uma boa prática fornecer um endereço de e-mail caso as pessoas queiram entrar em contato com você devido ao projeto.
  • URL é a URL do projeto. Essa URL pode ser o Web site do projeto, repositório Github ou qualquer URL que você queira. Novamente, essas informações são opcionais.

Pode ser útil também fornecer a licença e classificadores. Para mais informações sobre a criação de um arquivo setup.py, consulte a documentação do Python logo abaixo em Recursos.

Versão

Versões podem facilmente ser um tópico próprio, mas vale a pena mencioná-las no contexto de pacotes, pois um bom empacotamento envolve versões apropriadas. Versões são uma maneira de comunicar-se com o usuário: também permite que os usuários desenvolvam mais estabilidade e confiabilidade em seus aplicativos.

Com versões, o desenvolvedor diz aos usuários que ele mudou algo e dá limites explícitos para onde essas mudanças ocorreram.

Um padrão para versões em pacotes Python pode ser encontrado em Python Enhancement Proposal (PEP) 386. Essa proposta declara regras pragmáticas.

Mesmo que você não tenha lido e entendido a PEP, ou mesmo que não concorde com ela, seria sábio segui-la, pois mais e mais desenvolvedores Python estão acostumados a vê-la.

Além disso, versões não são apenas para releases estáveis transferidos por upload para PyPI, mas também são úteis para releases de desenvolvimento usando o sufixo devNN.

Geralmente não é bom fazer upload dessas versões de desenvolvedor para o PyPI, mas você ainda pode configurar seu próprio servidor de distribuição público (ou privado) para disponibilizá-las; dessa forma, usuários que queiram usar a versão mais recente podem citar isso em seu arquivo requirements.txt do pip. Aqui estão alguns exemplos de versões:

1.0.1        # 1.0.1 final release
1.0.2a # 1.0.2 Alpha (for Alpha, after Dev releases)
1.0.2a.dev5 # 1.0.2 Alpha, Dev release #5

Publicação

As pessoas geralmente não irão localizar e instalar software que não tenha sido publicado. Na maioria das vezes, você deve publicar seus pacotes no PyPI.

Após configurar o arquivo de configuração .pypirc, o comando upload passado para setup.py transmite seu pacote para o PyPI. Geralmente isso é feito em conjunto com o desenvolvimento de uma distribuição de origem:

python setup.py sdist upload

Se você estiver usando seu próprio servidor de distribuição, inclua uma seção para autorização em seu arquivo .pypirc para esse novo local, e indique-o por nome ao fazer o upload:

python setup.py sdist upload -r mydist

Configurar seu próprio servidor de distribuição

A principal razão para usar um servidor de distribuição próprio em software livre é oferecer um lugar para publicar releases de desenvolvedor, pois o PyPI deve consistir apenas de releases estáveis. Por exemplo, você provavelmente quer que instale o release estável mais recente localizado no PyPI:

pip install MyPackage

No entanto, se posteriormente você instalar releases de desenvolvedor, esse comando acabará instalando o release mais recente, o que significa o de desenvolvedor.

É geralmente bom fixar um release, mas nem todos os usuários fazem isso. Portanto, garanta que o release estável mais recente seja sempre retornado se o usuário não especificar um número de versão.

Uma maneira de ter as vantagens tanto de um método (expor apenas releases estáveis para padrão do pip) como do outro (permitir que os usuários instalem pacotes de releases de desenvolvedor) é hospedar um servidor de distribuição próprio. O projeto Pinax faz isso para todos os seus releases de desenvolvedor.

O servidor de distribuição é apenas um índice, servido em Protocolo de Transporte de Hipertexto (HTTP), de arquivos no seu servidor. Deve ter a seguinte estrutura de arquivos:

/index-name/package-name/package-name-version.tar.gz            

Dessa forma, é possível tornar o servidor privado configurando Basic-Auth no servidor da Web. É uma boa ideia incluir alguns recursos para upload de distribuições de origem também.

Para isso, é preciso incluir código para lidar com o upload, analisar o nome do arquivo e criar os caminhos de diretório para corresponder ao esquema acima. Essa estrutura existe para o projeto Pinax, que hospeda diversos repositórios.

pip e virtualenv

Embora este artigo tenha se concentrado primariamente na criação de pacotes, esta seção descreve o consumo de pacotes, oferecendo um pouco de apreciação para o que bons pacotes e versões fazem para os usuários.

pip é uma ferramenta que pode ser instalada diretamente, mas eu recomendo usá-la como parte de virtualenv. Recomendo usar virtualenv para tudo relacionado a Python, pois mantém os ambientes Python limpos.

Assim como uma máquina virtual permite executar diversos sistemas operacionais lado a lado, virtualenvs permitem executar diversos ambientes Python lado a lado. Eu não instalo nada no Python do meu sistema; em vez disso, crio um novo virtualenv para cada novo projeto ou utilitário em que trabalho.

Agora que você instalou virtualenv, pode brincar um pouco:

$ mkvirtualenv —no-site-packages testing
$ pip install Pinax
$ pip freeze|grep Pinax
$ pip uninstall Pinax
$ pip install —extra-index-url=http://dist.pinaxproject.com/fresh-start/
Pinax==0.9a2.dev1017
$ pip freeze|grep Pinax

Observe que a primeira instalação do pip foi transferida por download e instalada a partir do PyPI. pip freeze mostra todas as versões de pacotes instalados no virtualenv atual. pip uninstall faz exatamente o que você imagina: remove-se do virtualenv.

Em seguida, você instala uma versão de desenvolvedor do repositório novo para obter a versão de desenvolvimento do Pinax versão 0.9a2.dev1017.

Não é preciso ir para Web sites, fazer download de tarballs e criar links simbólicos para um pacote no site. (Era assim que eu costumava fazer, e causava muitos problemas.) Seus usuários obtêm tudo isso como resultado de bons pacotes, publicação e versões de seu projeto.

Conclusão

Em suma, vale muito a pena aprender a arte e ciência dos pacotes. Você obterá uma adoção maior dos usuários devido à facilidade de instalação e estabilidade que a divisão dos pacotes em versão oferece a eles.

Usando o modelo de setup.py fornecido abaixo em Recursos e discutido neste artigo, deve ser possível incluir pacotes em seu projeto rápido e facilmente. Comunicar-se com seus usuários por meio de versões apropriadas é uma questão de consideração com eles, pois facilita o rastreamento de mudanças entre releases.

Por fim, à medida que pip e virtualenv aumentam sua adoção, a confiança nos pacotes publicados — seja no PyPI ou em um servidor de distribuição próprio — aumenta. Portanto, não deixe de publicar os projetos que você quer compartilhar com o mundo.

Espero que este artigo tenha fornecido o suficiente para você começar. A seção Recursos deve fornecer documentação para ajudar a ir mais fundo. Se você tiver dúvidas, não hesite em pular no Freenode e me procurar em salas de bate-papo como #pinax e #django-social (com o apelido “paltman”) ou no Twitter (@paltman).

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Sobre o autor

Patrick Altman é um dos principais desenvolvedores do Pinax e criou e contribuiu para muitos outros projetos de software livre. Ele é o atual vice-presidente de engenharia da Eldarion. Anteriormente, atuou como engenheiro-chefe de software na StudioNow, a qual depois foi vendida para a AOL. Atualmente reside em Nashville, Tennessee, com sua esposa e três filhos.

Comentários