Existe uma maneira padrão de associar uma string de versão a um pacote python de forma que eu possa fazer o seguinte?
import foo
print foo.version
Eu imagino que há alguma maneira de recuperar esses dados sem nenhuma codificação extra, uma vez que as seqüências principais / secundárias já estão especificadas setup.py
. Solução alternativa que eu encontrei era para ter import __version__
no meu foo/__init__.py
e depois ter __version__.py
gerado por setup.py
.
setup.py
é suficiente. Veja esta pergunta .Respostas:
Não é uma resposta direta à sua pergunta, mas considere nomeá-la
__version__
, nãoversion
.Isso é quase um quase-padrão. Muitos módulos da biblioteca padrão usam
__version__
, e isso também é usado em muitos módulos de terceiros, por isso é quase-padrão.Geralmente,
__version__
é uma string, mas às vezes também é uma flutuação ou tupla.Edit: como mencionado por S.Lott (obrigado!), O PEP 8 diz explicitamente:
Você também deve garantir que o número da versão esteja em conformidade com o formato descrito no PEP 440 ( PEP 386, uma versão anterior desta norma).
fonte
__version_info__
especificamente? (Que "inventa" a sua própria palavra com sublinhado duplo.) [Quando James comentou, os sublinhados não fizeram nada nos comentários, agora eles indicam ênfase, então James__version_info__
também escreveu . --- ed.]Eu uso um único
_version.py
arquivo como o "local uma vez canônico" para armazenar as informações da versão:Ele fornece um
__version__
atributo.Ele fornece a versão padrão dos metadados. Portanto, ele será detectado por
pkg_resources
ou outras ferramentas que analisam os metadados do pacote (EGG-INFO e / ou PKG-INFO, PEP 0345).Ele não importa o seu pacote (ou qualquer outra coisa) ao criar o seu pacote, o que pode causar problemas em algumas situações. (Veja os comentários abaixo sobre quais problemas isso pode causar.)
Há apenas um local em que o número da versão é anotado; portanto, existe apenas um local para alterá-lo quando o número da versão é alterado e há menos chances de versões inconsistentes.
Eis como funciona: o "único local canônico" para armazenar o número da versão é um arquivo .py, chamado "_version.py", que está no seu pacote Python, por exemplo em
myniftyapp/_version.py
. Este arquivo é um módulo Python, mas o seu setup.py não o importa! (Isso anularia o recurso 3.) Em vez disso, o seu setup.py sabe que o conteúdo deste arquivo é muito simples, algo como:E assim o seu setup.py abre o arquivo e o analisa, com código como:
Em seguida, seu setup.py passa essa string como o valor do argumento "version" para
setup()
, satisfazendo o recurso 2.Para satisfazer o recurso 1, você pode fazer com que seu pacote (no tempo de execução, não no tempo de configuração!) Importe o arquivo _version da
myniftyapp/__init__.py
seguinte maneira:Aqui está um exemplo dessa técnica que uso há anos.
O código nesse exemplo é um pouco mais complicado, mas o exemplo simplificado que escrevi neste comentário deve ser uma implementação completa.
Aqui está o código de exemplo para importar a versão .
Se você encontrar algo errado com essa abordagem, entre em contato.
fonte
setup.py
. Além disso, se tentasse fazer profundidade total primeiro e executar todos os deps antes de executar este, ele ficaria preso se houvesse deps circulares. Mas se ele tentar compilar este pacote antes de instalar as dependências, se você importar o seu pacotesetup.py
, ele não poderá necessariamente importar seus deps ou as versões corretas dos deps.execfile("myniftyapp/_version.py")
de dentro do arquivo setup.py, em vez de tentar analisar o código da versão manualmente. Sugerido em stackoverflow.com/a/2073599/647002 - a discussão também pode ser útil.Reescrito 2017-05
Após mais de dez anos escrevendo código Python e gerenciando vários pacotes, cheguei à conclusão de que o DIY talvez não seja a melhor abordagem.
Comecei a usar o
pbr
pacote para lidar com o controle de versão em meus pacotes. Se você estiver usando o git como seu SCM, isso caberá no seu fluxo de trabalho como mágica, economizando suas semanas de trabalho (você ficará surpreso com a complexidade do problema).Atualmente, o pbr está classificado como o 11º pacote python mais usado e não atingiu nenhum truque sujo: era apenas um: corrigir um problema de empacotamento comum de uma maneira muito simples.
pbr
pode fazer mais da carga de manutenção de pacote, não se limita à versão, mas não o força a adotar todos os seus benefícios.Então, para lhe dar uma idéia de como parece adotar o pbr em um commit, dê uma olhada na embalagem do pbr
Provavelmente, você observaria que a versão não está armazenada no repositório. O PBR o detecta nas ramificações e tags do Git.
Não é necessário se preocupar com o que acontece quando você não possui um repositório git porque o pbr "compila" e armazena em cache a versão quando você empacota ou instala os aplicativos, para que não haja dependência de tempo de execução no git.
Solução antiga
Aqui está a melhor solução que eu já vi até agora e também explica o porquê:
Dentro
yourpackage/version.py
:Dentro
yourpackage/__init__.py
:Dentro
setup.py
:Se você conhece outra abordagem que parece melhor, me avise.
fonte
from .version import __version__
no setup.py também?setup.py
está em execução - experimentá-lo, você obterá um erro (ou, pelo menos, eu fiz :-))De acordo com o PEP 396 diferido (números de versão do módulo) , existe uma maneira proposta de fazer isso. Descreve, com justificativa, um padrão (reconhecidamente opcional) para os módulos seguirem. Aqui está um trecho:
fonte
Embora isso provavelmente seja tarde demais, há uma alternativa um pouco mais simples para a resposta anterior:
(E seria bastante simples converter partes de números de versão com incremento automático em uma string usando
str()
.)Obviamente, pelo que vi, as pessoas tendem a usar algo como a versão mencionada anteriormente ao usá-la
__version_info__
e, como tal, armazenam-na como uma tupla de ints; no entanto, não entendo bem o motivo, pois duvido que existam situações nas quais você executaria operações matemáticas, como adição e subtração em partes de números de versão para qualquer finalidade, além de curiosidade ou auto-incremento (e mesmo assim,int()
estr()
pode ser usado com bastante facilidade). (Por outro lado, existe a possibilidade do código de outra pessoa esperar uma tupla numérica em vez de uma tupla de string e, portanto, falhar.)Essa é, é claro, minha própria visão, e eu gostaria com prazer da opinião de outras pessoas sobre o uso de uma tupla numérica.
Como shezi me lembrou, comparações (lexicais) de cadeias de números não têm necessariamente o mesmo resultado que comparações numéricas diretas; zeros à esquerda seriam necessários para prover isso. Portanto, no final, o armazenamento
__version_info__
(ou o que seria chamado) como uma tupla de valores inteiros permitiria comparações de versões mais eficientes.fonte
__version_info__ = (1,2,3)
__version_info__ = (0, 1, 0) __version__ = '.'.join(map(str, __version_info__))
__version__ = '.'.join(__version_info__)
é que__version_info__ = ('1', '2', 'beta')
se tornará1.2.beta
, não1.2beta
ou1.2 beta
Muitas dessas soluções aqui ignoram as
git
tags de versão, o que ainda significa que você precisa rastrear a versão em vários locais (ruim). Abordei isso com os seguintes objetivos:git
repositóriogit tag
/push
esetup.py upload
etapas com um único comando que não aceita entradas.Como funciona:
Em um
make release
comando, a última versão marcada no repositório git é encontrada e incrementada. A tag é enviada de volta paraorigin
.Ele
Makefile
armazena a versão emsrc/_version.py
que ela será lidasetup.py
e também incluída no release. Não verifique_version.py
no controle de origem!setup.py
O comando lê a nova string de versão depackage.__version__
.Detalhes:
Makefile
O
release
destino sempre incrementa o dígito da terceira versão, mas você pode usar onext_minor_ver
ounext_major_ver
para incrementar os outros dígitos. Os comandos dependem doversionbump.py
script verificado na raiz do repositórioversionbump.py
Isso faz o trabalho pesado de como processar e incrementar o número da versão de
git
.__init__.py
O
my_module/_version.py
arquivo é importado paramy_module/__init__.py
. Coloque qualquer configuração de instalação estática aqui que você deseja distribuir com seu módulo.setup.py
O último passo é ler as informações da versão no
my_module
módulo.Obviamente, para que tudo isso funcione, você precisará ter pelo menos uma tag de versão no seu repositório para começar.
fonte
versionbump.py
quando temos um pacote impressionante de bumpversion para python._version.py
ser rastreado com controle de versão?Eu uso um arquivo JSON no diretório do pacote. Isso se encaixa nos requisitos da Zooko.
Dentro
pkg_dir/pkg_info.json
:Dentro
setup.py
:Dentro
pkg_dir/__init__.py
:Eu também coloquei outras informações
pkg_info.json
, como autor. Eu gosto de usar JSON porque posso automatizar o gerenciamento de metadados.fonte
Também digno de nota é que, além de
__version__
ser um semi-std. no python, então é__version_info__
uma tupla, nos casos simples, você pode fazer algo como:... e você pode obter a
__version__
string de um arquivo, ou qualquer outra coisa.fonte
__version_info__
?__version_info__ = (1, 2, 3)
e__version__ = '.'.join(map(str, __version_info__))
).__version__ = '.'.join(str(i) for i in __version_info__)
- um pouco mais longo, mas mais pitônico.i
não tem significado,version_num
é um pouco longo e ambíguo ...). Eu até considero a existência domap()
Python como uma forte dica de que ele deve ser usado aqui, pois o que precisamos fazer aqui é o caso de uso típico demap()
(uso com uma função existente) - não vejo muitos outros usos razoáveis.Não parece haver uma maneira padrão de incorporar uma string de versão em um pacote python. A maioria dos pacotes que vi usam alguma variante da sua solução, ou seja, eitner
Incorpore a versão
setup.py
esetup.py
gere um módulo (por exemploversion.py
) contendo apenas informações da versão, importadas pelo seu pacote ouO inverso: colocar a informação de versão em sua própria embalagem, e importação que para definir a versão em
setup.py
fonte
A seta lida com isso de uma maneira interessante.
Agora (desde 2e5031b )
Em
arrow/__init__.py
:Em
setup.py
:Antes
Em
arrow/__init__.py
:Em
setup.py
:fonte
file_text
?pip install -e .
em uma ramificação de desenvolvimento ou algo durante o teste. O setup.py não deve absolutamente importar a importação do pacote que está em processo de instalação para determinar os parâmetros para a implantação. Caramba.Eu também vi outro estilo:
fonte
.VERSION
não significa que você não precisa implementá-lo__version__
.django
no projeto?Usando
setuptools
epbr
Não existe uma maneira padrão de gerenciar versão, mas a maneira padrão de gerenciar seus pacotes é
setuptools
.A melhor solução que encontrei no geral para gerenciar a versão é usar
setuptools
com apbr
extensão. Esta é agora a minha maneira padrão de gerenciar versão.A configuração do seu projeto para o pacote completo pode ser um exagero para projetos simples, mas se você precisar gerenciar a versão, provavelmente estará no nível certo para definir tudo. Fazer isso também torna seu pacote liberável no PyPi para que todos possam fazer o download e usá-lo com o Pip.
O PBR move a maioria dos metadados das
setup.py
ferramentas e para umsetup.cfg
arquivo que é usado como fonte para a maioria dos metadados, que pode incluir a versão. Isso permite que os metadados sejam empacotados em um executável usando algo comopyinstaller
se necessário (nesse caso, você provavelmente precisará dessas informações ) e separa os metadados dos outros scripts de gerenciamento / configuração de pacotes. Você pode atualizar diretamente a string de versãosetup.cfg
manualmente, e ela será puxada para a*.egg-info
pasta ao criar as versões do pacote. Seus scripts podem acessar a versão a partir dos metadados usando vários métodos (esses processos são descritos nas seções abaixo).Ao usar o Git para VCS / SCM, essa configuração é ainda melhor, pois extrai muitos metadados do Git para que seu repo possa ser sua principal fonte de verdade para alguns dos metadados, incluindo versão, autores, changelogs, etc. Para a versão especificamente, ele criará uma string de versão para o commit atual com base nas tags git no repositório.
setup.py
e umsetup.cfg
arquivo com os metadados.Como o PBR puxa a versão, o autor, o changelog e outras informações diretamente do seu repositório git, então alguns dos metadados
setup.cfg
podem ser deixados de fora e gerados automaticamente sempre que uma distribuição é criada para o seu pacote (usandosetup.py
)Versão atual em tempo real
setuptools
extrairá as informações mais recentes em tempo real usandosetup.py
:Isso puxará a versão mais recente do
setup.cfg
arquivo ou do repositório git, com base na confirmação mais recente que foi feita e nas tags existentes no repositório. Este comando não atualiza a versão em uma distribuição.Atualizando a versão
Quando você cria uma distribuição com
setup.py
(py setup.py sdist
por exemplo, por exemplo), todas as informações atuais serão extraídas e armazenadas na distribuição. Essencialmente, ele executa osetup.py --version
comando e armazena as informações da versão napackage.egg-info
pasta em um conjunto de arquivos que armazenam metadados de distribuição.Acessando a versão de um script
Você pode acessar os metadados da compilação atual nos scripts Python no próprio pacote. Por versão, por exemplo, existem várias maneiras de fazer isso que encontrei até agora:
Você pode colocar um desses diretamente no seu
__init__.py
para o pacote extrair as informações da versão da seguinte maneira, semelhante a algumas outras respostas:fonte
Depois de várias horas tentando encontrar a solução mais simples e confiável, aqui estão as partes:
crie um arquivo version.py DENTRO da pasta do seu pacote "/ mypackage":
em setup.py:
na pasta principal init .py:
A
exec()
função executa o script fora de qualquer importação, pois o setup.py é executado antes que o módulo possa ser importado. Você ainda precisa gerenciar o número da versão em um arquivo em um só lugar, mas infelizmente ele não está no setup.py. (essa é a desvantagem, mas não ter bugs de importação é a vantagem)fonte
Muito trabalho para a versão uniforme e em apoio às convenções foi concluído desde que essa pergunta foi feita pela primeira vez . Opções palatáveis agora estão detalhadas no Guia do Usuário de Empacotamento do Python . Também digno de nota é que os esquemas de número de versão são relativamente rigorosos no Python, de acordo com o PEP 440 , e, portanto, manter as coisas sãs é fundamental se o seu pacote for lançado na Cheese Shop .
Aqui está uma descrição resumida das opções de versão:
setup.py
( setuptools ) e obtenha a versão.__init__.py
controle quanto o de origem), por exemplo , bump2version , changes ou zest.releaser .__version__
variável global em um módulo específico.setup.py
liberação e use importlib.metadata para buscá-lo em tempo de execução. (Aviso, existem versões pré-3.8 e pós-3.8.)__version__
insample/__init__.py
e importe a amostra emsetup.py
.Observe que (7) pode ser a abordagem mais moderna (os metadados da compilação são independentes do código, publicado pela automação). Observe também que, se a instalação for usada para a liberação do pacote, um simples
python3 setup.py --version
relatará a versão diretamente.fonte
Para o que vale a pena, se você estiver usando distutils NumPy,
numpy.distutils.misc_util.Configuration
tem ummake_svn_version_py()
método que incorpora o número de revisão dentropackage.__svn_version__
da variávelversion
.fonte
version.py
arquivo apenas com__version__ = <VERSION>
param no arquivo. Nosetup.py
arquivo, importe o__version__
parâmetro e coloque seu valor nosetup.py
arquivo assim:version=__version__
setup.py
arquivo comversion=<CURRENT_VERSION>
- o CURRENT_VERSION é codificado.Como não queremos alterar manualmente a versão do arquivo toda vez que criamos uma nova tag (pronta para lançar uma nova versão do pacote), podemos usar o seguinte ..
Eu recomendo o pacote bumpversion . Eu tenho usado por anos para encontrar uma versão.
comece adicionando
version=<VERSION>
ao seusetup.py
arquivo, se ainda não o tiver.Você deve usar um script curto como este toda vez que encontrar uma versão:
Em seguida, adicione um arquivo por repositório chamado
.bumpversion.cfg
::Nota:
__version__
parâmetro noversion.py
arquivo como sugerido em outras postagens e atualizar o arquivo bumpversion assim:[bumpversion:file:<RELATIVE_PATH_TO_VERSION_FILE>]
git commit
ougit reset
tudo no seu repo, caso contrário, você receberá um erro de repo sujo.fonte
bumpversion
, sem ele não funcionará. Use a versão mais recente.version.py
ou com elabumpversion
?__version__
valor do parâmetro para o arquivo setup.py. Minha solução é usada na produção e é uma prática comum. Nota: para deixar claro, usar o bumpversion como parte de um script é a melhor solução, coloque-o no seu IC e será uma operação automática.Se você usa o CVS (ou RCS) e deseja uma solução rápida, pode usar:
(Obviamente, o número da revisão será substituído por você pelo CVS.)
Isso fornece uma versão para impressão e informações sobre a versão que você pode usar para verificar se o módulo que você está importando possui pelo menos a versão esperada:
fonte
__version__
? Como incrementar o número da versão com esta solução?