Mantendo uma única fonte da versão do pacote¶
Existem muitas técnicas para manter uma única fonte para o número de versão do seu projeto:
Leia o arquivo em
setup.py
e obtenha a versão. Exemplo (de pip setup.py):import codecs import os.path def read(rel_path): here = os.path.abspath(os.path.dirname(__file__)) with codecs.open(os.path.join(here, rel_path), 'r') as fp: return fp.read() def get_version(rel_path): for line in read(rel_path).splitlines(): if line.startswith('__version__'): delim = '"' if '"' in line else "'" return line.split(delim)[1] else: raise RuntimeError("Unable to find version string.") setup( ... version=get_version("package/__init__.py") ... )
Nota
A partir do lançamento do setuptools 46.4.0, pode-se realizar a mesma coisa colocando o seguinte no arquivo
setup.cfg
do projeto (substituindo “pacote” pelo nome de importação do pacote):[metadata] version = attr: package.__version__
A partir do lançamento do setuptools 61.0.0, pode-se especificar a versão dinamicamente no arquivo
pyproject.toml
do projeto.[project] name = "package" dynamic = ["version"] [tool.setuptools.dynamic] version = {attr = "package.__version__"}
Esteja ciente de que os indicadores de configuração declarativos, incluindo a diretiva
attr:
, não são suportados em parâmetros parasetup.py
.Use uma ferramenta de construção externa que gerencia a atualização de ambos os locais ou oferece uma API que ambos os locais podem usar.
Poucas ferramentas que você poderia usar, sem nenhuma ordem específica, e não necessariamente completas: bump2version, changes, commitizen, zest.releaser.
Defina o valor para uma variável global
__version__
em um módulo dedicado em seu projeto (por exemplo,version.py
), então faça com quesetup.py
leia e execute (exec
) o valor em uma variável.version = {} with open("...sample/version.py") as fp: exec(fp.read(), version) # later on we use: version['__version__']
Exemplo usando esta técnica: warehouse.
Coloque o valor em um arquivo de texto simples
VERSION
e tenha ambossetup.py
e o código do projeto lidos.with open(os.path.join(mypackage_root_dir, 'VERSION')) as version_file: version = version_file.read().strip()
Uma vantagem dessa técnica é que ela não é específica do Python. Qualquer ferramenta pode ler a versão.
Aviso
Com esta abordagem, você deve se certificar de que o arquivo
VERSION
está incluído em todas as suas distribuições de fonte e binárias (por exemplo, adicioneinclude VERSION
ao seuMANIFEST.in
).Defina o valor em
setup.py
e faça com que o código do projeto use a APIimportlib.metadata
para buscar o valor em tempo de execução. (importlib.metadata
foi introduzido no Python 3.8 e está disponível para versões anteriores como o projetoimportlib-metadata
.) A versão de um projeto instalado pode ser obtida com a API da seguinte forma:import sys if sys.version_info >= (3, 8): from importlib import metadata else: import importlib_metadata as metadata assert metadata.version('pip') == '1.2.0'
Esteja ciente de que a API
importlib.metadata
só sabe sobre o que está nos metadados de instalação, o que não é necessariamente o código que está importado no momento.Se um projeto usa este método para buscar sua versão em tempo de execução, então seu valor
install_requires
precisa ser editado para instalarimportlib-metadata
em versões pré-3.8 do Python como:setup( ... install_requires=[ ... 'importlib-metadata >= 1.0 ; python_version < "3.8"', ... ], ... )
’Uma alternativa mais antiga (e menos eficiente) ao
importlib.metadata
é a APIpkg_resources
fornecida pelosetuptools
:import pkg_resources assert pkg_resources.get_distribution('pip').version == '1.2.0'
Se um projeto usa
pkg_resources
para buscar sua própria versão em tempo de execução, entãosetuptools
deve ser adicionado à listainstall_requires
do projeto.Exemplo usando esta técnica: setuptools.
Defina o valor para
__version__
emsample/__init__.py
e importesample
nosetup.py
.import sample setup( ... version=sample.__version__ ... )
Aviso
Embora esta técnica seja comum, esteja ciente que ela vai falhar se
sample/__init__.py
importar pacotes de dependênciasinstall_requires
, que muito provavelmente ainda não estarão instalados quandosetup.py
for executado.Mantenha o número da versão nas tags de um sistema de controle de versão (Git, Mercurial, etc), em vez de no código, e extraia-o automaticamente de lá usando setuptools_scm.