326

次のような方法でバージョン文字列を Python パッケージに関連付ける標準的な方法はありますか?

import foo
print(foo.version)

setup.pyマイナー/メジャー文字列が既に指定されているため、追加のハードコーディングなしでそのデータを取得する方法があると思います。私が見つけた別の解決策は、import __version__私の中にfoo/__init__.pyあり、それからによって__version__.py生成されましたsetup.py

4

21 に答える 21

170

__version__質問に対する直接の回答ではありませんが、 ではなくという名前を付けることを検討する必要がありますversion

これはほぼ準標準です。標準ライブラリの多くのモジュールは を使用__version__しており、これは多くのサードパーティ モジュールでも使用されているため、準標準です。

通常__version__は文字列ですが、float や tuple の場合もあります。

編集: S.Lott が述べたように (ありがとう!)、PEP 8は明示的にそれを言います:

モジュールレベルのダンダー名

__all____author__、などのモジュール レベルの "dunders" (つまり、先頭 2 つと末尾 2 つのアンダースコアを持つ名前)__version__は、モジュール docstring の後、インポート以外のすべてのインポート ステートメントの前に配置する必要があります__future__

また、バージョン番号がPEP 440 (この標準の以前のバージョンであるPEP 386 )で説明されている形式に準拠していることを確認する必要があります。

于 2009-01-19T21:13:57.973 に答える
119

2017-05 改訂

13 年以上 Python コードを書き、さまざまなパッケージを管理してきた結果、DIY は最善の方法ではないという結論に達しました。

pbrパッケージのバージョン管理を扱うためにパッケージを使い始めました。git を SCM として使用している場合、これは魔法のようにワークフローに適合し、数週間の作業を節約できます (問題がどれほど複雑であるかに驚かれることでしょう)。

今日の時点で、pbr の月間ダウンロード数は 1,200 万回で、このレベルに到達するのに汚いトリックは含まれていません。それはたった 1 つのことでした。一般的なパッケージングの問題を非常に簡単な方法で修正することです。

pbrパッケージ メンテナンスの負担を軽減でき、バージョン管理に限定されませんが、すべての利点を採用する必要はありません。

したがって、1 つのコミットで pbr を採用することがどのように見えるかについてのアイデアを提供するために、pbr へのパッケージングの切り替えを見てください。

おそらく、バージョンがリポジトリにまったく保存されていないことに気付くでしょう。PBR は Git ブランチとタグからそれを検出します。

アプリケーションをパッケージ化またはインストールするときに pbr がバージョンを「コンパイル」してキャッシュするため、git リポジトリがない場合に何が起こるかを心配する必要はありません。そのため、git に対するランタイム依存関係はありません。

古いソリューション

これは私がこれまでに見た中で最良の解決策であり、その理由も説明しています:

内部yourpackage/version.py:

# Store the version here so:
# 1) we don't load dependencies by storing it in __init__.py
# 2) we can import it in setup.py for the same reason
# 3) we can import it into your module module
__version__ = '0.12'

内部yourpackage/__init__.py:

from .version import __version__

内部setup.py:

exec(open('yourpackage/version.py').read())
setup(
    ...
    version=__version__,
    ...

より良いと思われる別のアプローチを知っている場合は、お知らせください。

于 2013-04-18T13:50:57.040 に答える
31

deferred PEP 396 (Module Version Numbers) に従って、これを行う方法が提案されています。それは、理論的根拠とともに、モジュールが従うべき標準 (確かにオプション) を説明しています。ここにスニペットがあります:

3) モジュール (またはパッケージ) にバージョン番号が含まれている場合、バージョンは__version__属性で使用できる必要があります。

4) 名前空間パッケージ内に存在するモジュールの場合、モジュールは__version__属性を含める必要があります。名前空間パッケージ自体は、独自の__version__属性を含めるべきではありません。

5)__version__属性の値は文字列であるべきです。

于 2013-04-11T15:16:03.027 に答える
28

これはおそらく遅すぎるかもしれませんが、前の回答に代わる少し簡単な方法があります。

__version_info__ = ('1', '2', '3')
__version__ = '.'.join(__version_info__)

(また、バージョン番号の自動インクリメント部分を を使用して文字列に変換するのはかなり簡単str()です。)

もちろん、私が見たところ、人々は を使用するときに前述のバージョンのようなものを使用する傾向があり、それ__version_info__を int のタプルとして保存します。ただし、好奇心や自動インクリメント以外の目的で、バージョン番号の一部に対して加算や減算などの数学演算を実行する状況があるとは思えないため、そうすることの意味がよくわかりません (その場合でも、かなり簡単に使用できます)int()str()(一方で、他の誰かのコードが文字列タプルではなく数値タプルを期待しているため、失敗する可能性があります。)

もちろん、これは私自身の見解であり、数値タプルの使用について他の人からの意見を歓迎します。


shezi が思い出したように、数値文字列の (レキシカル) 比較は、直接の数値比較と必ずしも同じ結果になるとは限りません。そのためには先行ゼロが必要です。したがって、最終的には__version_info__、整数値のタプルとして (またはそれが何と呼ばれるかを問わず) 格納すると、より効率的なバージョン比較が可能になります。

于 2009-07-15T14:29:04.647 に答える
9

この質問が最初に出されて以来、統一されたバージョニングと規約のサポートに向けた多くの作業が完了しました。適切なオプションについては、Python Packaging User Guideで詳しく説明されています。また注目に値するのは、Python ではバージョン番号スキームが PEP 440 に従って比較的厳密であるため、パッケージがCheese Shopにリリースされる場合は、物事を正常に保つことが重要です。

バージョン管理オプションの簡略化された内訳は次のとおりです。

  1. setup.py( setuptools )でファイルを読み取り、バージョンを取得します。
  2. 外部ビルド ツール (両方__init__.pyとソース管理を更新するため) を使用します (例: bump2versionchangesまたはzest.releaser ) 。
  3. __version__特定のモジュールのグローバル変数に値を設定します。
  4. setup.py とコードの両方が読み取れるように、単純な VERSION テキスト ファイルに値を配置します。
  5. setup.pyリリースを介して値を設定し、importlib.metadataを使用して実行時に取得します。(警告、3.8 より前のバージョンと 3.8 より後のバージョンがあります。)
  6. 値を__version__in に設定し、sample/__init__.pyサンプルを にインポートしsetup.pyます。
  7. setuptools_scmを使用してソース管理からバージョン管理を抽出し、それがコードではなく正規の参照になるようにします。

(7) が最も最新のアプローチである可能性があることに注意してください (ビルド メタデータはコードから独立しており、自動化によって公開されます)。また、パッケージのリリースに setup が使用されている場合、単純なバージョンが直接報告されることに注意してください。python3 setup.py --version

于 2020-05-22T17:03:10.787 に答える
7

また、注目に値するのは__version__、半標準であるだけでなく、それです。Python__version_info__では、これはタプルです。単純なケースでは、次のようなことができます。

__version__ = '1.2.3'
__version_info__ = tuple([ int(num) for num in __version__.split('.')])

...そして__version__、ファイルなどから文字列を取得できます。

于 2009-01-21T19:44:24.813 に答える
5

私はまた別のスタイルを見ました:

>>> django.VERSION
(1, 1, 0, 'final', 0)
于 2009-10-11T17:32:47.197 に答える
5

Python パッケージにバージョン文字列を埋め込む標準的な方法はないようです。私が見たほとんどのパッケージは、ソリューションのいくつかのバリアントを使用しています。つまり、eitner

  1. バージョンを埋め込み、パッケージによってインポートされたバージョン情報のみを含むモジュール (例: ) を生成するsetup.py、またはsetup.pyversion.py

  2. 逆: パッケージ自体にバージョン情報を入力し、それをインポートてバージョンを設定し ます。setup.py

于 2009-01-19T18:49:58.027 に答える
5

アローはそれを興味深い方法で処理します。

現在 ( 2e5031b以降)

arrow/__init__.py

__version__ = 'x.y.z'

setup.py

from arrow import __version__

setup(
    name='arrow',
    version=__version__,
    # [...]
)

arrow/__init__.py

__version__ = 'x.y.z'
VERSION = __version__

setup.py

def grep(attrname):
    pattern = r"{0}\W*=\W*'([^']+)'".format(attrname)
    strval, = re.findall(pattern, file_text)
    return strval

file_text = read(fpath('arrow/__init__.py'))

setup(
    name='arrow',
    version=grep('__version__'),
    # [...]
)
于 2016-10-26T12:59:55.950 に答える
1
  1. _version.txtと同じフォルダにby という名前のファイルを作成し、__init__.pyバージョンを 1 行で記述します。
0.8.2
  1. _version.txtのファイルからこの情報を読み取ります__init__.py:
    import os 
    def get_version():
        with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), "_version.txt")) as f:
            return f.read().strip() 
    __version__ = get_version()
于 2021-03-12T13:46:54.897 に答える
-3

価値があるのは、NumPy distutils を使用している場合numpy.distutils.misc_util.Configuration、リビジョン番号を変数make_svn_version_py()内に埋め込むメソッドがあります。package.__svn_version__version

于 2009-01-19T18:42:23.910 に答える