6. Exemplos de Distutils¶
Nota
Este documento está sendo mantido apenas até que a documentação do setuptools
em https://setuptools.readthedocs.io/en/latest/setuptools.html cubra independentemente todas as informações relevantes atualmente incluídas aqui.
Este capítulo fornece vários exemplos básicos para ajudar a começar com distutils. Informações adicionais sobre o uso de distutils podem ser encontradas no Distutils Cookbook.
Ver também
- Distutils Cookbook
Coleção de receitas mostrando como obter mais controle sobre distutils.
6.1. Distribuição Python pura (por módulo)¶
Se você está apenas distribuindo alguns módulos, especialmente se eles não residem em um pacote específico, você pode especificá-los individualmente usando a opção py_modules
no script de instalação.
No caso mais simples, você terá dois arquivos com os quais se preocupar: um script de instalação e o único módulo que você está distribuindo foo.py
neste exemplo:
<root>/
setup.py
foo.py
(Em todos os diagramas desta seção, <root> se refere ao diretório raiz da distribuição.) Um script de instalação mínimo para descrever essa situação seria:
from distutils.core import setup
setup(name='foo',
version='1.0',
py_modules=['foo'],
)
Observe que o nome da distribuição é especificado independentemente com a opção name
, e não existe uma regra que diga que deve ser igual ao nome do único módulo na distribuição (embora seja provavelmente uma boa convenção a seguir ) No entanto, o nome da distribuição é usado para gerar nomes de arquivos, portanto, você deve usar letras, dígitos, sublinhados e hífenes.
Como py_modules
é uma lista, é claro que você pode especificar vários módulos, por exemplo. se você estiver distribuindo os módulos foo
e bar
, sua configuração poderá ser assim:
<root>/
setup.py
foo.py
bar.py
e o script de configuração pode ser
from distutils.core import setup
setup(name='foobar',
version='1.0',
py_modules=['foo', 'bar'],
)
Você pode colocar os arquivos fonte do módulo em outro diretório, mas se você tiver módulos suficientes para fazer isso, provavelmente será mais fácil especificar módulos por pacote do que listá-los individualmente.
6.2. Distribuição Python pura (por pacote)¶
Se você tiver mais do que alguns módulos para distribuir, especialmente se estiverem em vários pacotes, provavelmente será mais fácil especificar pacotes inteiros do que módulos individuais. Isso funciona mesmo que seus módulos não estejam em um pacote; você pode simplesmente dizer ao Distutils para processar os módulos do pacote raiz, e isso funciona da mesma forma que em qualquer outro pacote (exceto que você não precisa ter um arquivo __init__.py
).
O script de instalação do último exemplo também pode ser escrito como
from distutils.core import setup
setup(name='foobar',
version='1.0',
packages=[''],
)
(A string vazia representa o pacote raiz.)
Se esses dois arquivos forem movidos para um subdiretório, mas permanecerem no pacote raiz, por exemplo:
<root>/
setup.py
src/ foo.py
bar.py
você ainda especificaria o pacote raiz, mas precisará informar ao Distutils onde estão os arquivos fonte no pacote raiz:
from distutils.core import setup
setup(name='foobar',
version='1.0',
package_dir={'': 'src'},
packages=[''],
)
Mais tipicamente, porém, você deseja distribuir vários módulos no mesmo pacote (ou em subpacotes). Por exemplo, se os módulos foo
e bar
pertencem ao pacote foobar
, uma maneira de fazer o layout da sua árvore de fontes é
<root>/
setup.py
foobar/
__init__.py
foo.py
bar.py
Na verdade, esse é o layout padrão esperado pelo Distutils e o que exige menos trabalho para descrever no seu script de instalação:
from distutils.core import setup
setup(name='foobar',
version='1.0',
packages=['foobar'],
)
Se você quiser colocar módulos em diretórios não nomeados para o pacote, precisará usar a opção package_dir
novamente. Por exemplo, se o diretório src
contiver módulos no pacote foobar
:
<root>/
setup.py
src/
__init__.py
foo.py
bar.py
um script de instalação apropriado seria
from distutils.core import setup
setup(name='foobar',
version='1.0',
package_dir={'foobar': 'src'},
packages=['foobar'],
)
Ou, você pode colocar módulos do seu pacote principal diretamente na raiz da distribuição:
<root>/
setup.py
__init__.py
foo.py
bar.py
nesse caso, seu script de instalação seria
from distutils.core import setup
setup(name='foobar',
version='1.0',
package_dir={'foobar': ''},
packages=['foobar'],
)
(A string vazia também representa o diretório atual.)
Se você possui subpacotes, eles devem ser listados explicitamente em packages
, mas qualquer entrada em package_dir
se estende automaticamente aos subpacotes. (Em outras palavras, o Distutils não varre sua árvore de fontes, tentando descobrir quais diretórios correspondem aos pacotes Python procurando __init__.py
.) Portanto, se o layout padrão aumentar um subpacote:
<root>/
setup.py
foobar/
__init__.py
foo.py
bar.py
subfoo/
__init__.py
blah.py
então o script de instalação correspondente seria
from distutils.core import setup
setup(name='foobar',
version='1.0',
packages=['foobar', 'foobar.subfoo'],
)
6.3. Módulo de extensão única¶
Os módulos de extensão são especificados usando a opção ext_modules
. package_dir
não afeta onde os arquivos de origem das extensões são encontrados; isso afeta apenas a fonte dos módulos Python puros. O caso mais simples, um único módulo de extensão em um único arquivo fonte C, é:
<root>/
setup.py
foo.c
Se a extensão foo
pertencer ao pacote raiz, o script de instalação para isso pode ser
from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
version='1.0',
ext_modules=[Extension('foo', ['foo.c'])],
)
Se a extensão realmente pertence a um pacote, digamos foopkg
, então
Com exatamente o mesmo layout da árvore de fontes, esta extensão pode ser colocada no pacote foopkg
simplesmente alterando o nome da extensão:
from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
version='1.0',
ext_modules=[Extension('foopkg.foo', ['foo.c'])],
)
6.4. Verificando um pacote¶
O comando check
permite verificar se os metadados do seu pacote atendem aos requisitos mínimos para construir uma distribuição.
Para executá-lo, basta chamá-lo usando o script setup.py
. Se algo estiver faltando, check
exibirá um aviso.
Vamos dar um exemplo com um script simples:
from distutils.core import setup
setup(name='foobar')
A execução do comando check
exibirá alguns avisos:
$ python setup.py check
running check
warning: check: missing required meta-data: version, url
warning: check: missing meta-data: either (author and author_email) or
(maintainer and maintainer_email) should be supplied
Se você usar a sintaxe reStructuredText no campo long_description
e o docutils estiver instalado, poderá verificar se a sintaxe está correta com o comando check
, usando a opção restructuredtext
.
Por exemplo, se o script setup.py
for alterado assim:
from distutils.core import setup
desc = """\
My description
==============
This is the description of the ``foobar`` package.
"""
setup(name='foobar', version='1', author='tarek',
author_email='tarek@ziade.org',
url='http://example.com', long_description=desc)
Onde a descrição longa está quebrada, check
poderá detectá-la usando o analisador docutils
:
$ python setup.py check --restructuredtext
running check
warning: check: Title underline too short. (line 2)
warning: check: Could not finish the parsing.
6.5. Lendo os metadados¶
A função distutils.core.setup()
fornece uma interface de linha de comando que permite consultar os campos de metadados de um projeto através do script setup.py
de um projeto fornecido:
$ python setup.py --name
distribute
Essa chamada lê os metadados name
executando a função distutils.core.setup()
. Embora, quando uma distribuição de origem ou binária é criada com o Distutils, os campos de metadados sejam gravados em um arquivo estático chamado PKG-INFO
. Quando um projeto baseado no Distutils é instalado no Python, o arquivo PKG-INFO
é copiado juntamente com os módulos e pacotes da distribuição em NOME-VERSÃO-pyX.X.egg-info
, em que NOME
é o nome do projeto, VERSÃO
sua versão conforme definida nos metadados e pyX.X
a versão principal e secundária do Python, como 2.7
ou 3.2
.
Você pode ler novamente esse arquivo estático usando a classe distutils.dist.DistributionMetadata
e seu método read_pkg_file()
:
>>> from distutils.dist import DistributionMetadata
>>> metadata = DistributionMetadata()
>>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info'))
>>> metadata.name
'distribute'
>>> metadata.version
'0.6.8'
>>> metadata.description
'Easily download, build, install, upgrade, and uninstall Python packages'
Observe que a classe também pode ser instanciada com um caminho de arquivo de metadados para carregar seus valores:
>>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info'
>>> DistributionMetadata(pkg_info_path).name
'distribute'