importlib.metadata -- パッケージメタデータへのアクセス

Added in version 3.8.

バージョン 3.10 で変更: importlib.metadata は暫定的なものではなくなりました。

ソースコード: Lib/importlib/metadata/__init__.py

importlib.metadata はインストールされた 配布パッケージ のエントリポイントやトップレベル名 (あれば、 パッケージ やモジュール) のようなメタデータへのアクセスを提供するライブラリです。Pythonのインポートシステムをベースに構築されており、このライブラリは pkg_resourcesentry point APImetadata API にある同様の機能を置き換えることを目的としています。importlib.resources と共に、このパッケージは古くて効率の悪い pkg_resources パッケージを使う必要性を無くすことができます。

importlib.metadata は、Pythonの site-packages ディレクトリに pip などのツールでインストールしたサードパーティの 配布パッケージ に対して動作します。具体的には、 dist-infoegg-info ディレクトリを持つ配布物や、 コアとなるメタデータの仕様 で定義されたメタデータを検出できるようにします。

重要

These are not necessarily equivalent to or correspond 1:1 with the top-level import package names that can be imported inside Python code. One distribution package can contain multiple import packages (and single modules), and one top-level import package may map to multiple distribution packages if it is a namespace package. You can use package_distributions() to get a mapping between them.

デフォルトでは、配布物のメタデータはファイルシステム上、または sys.path のzipアーカイブに保存されます。拡張機構により、メタデータはほとんどどこにでも置くことができます。

参考

https://importlib-metadata.readthedocs.io/

importlib_metadata のドキュメントは importlib.metadata のバックポートです。これには、このモジュールのクラスと関数の APIリファレンス と、 pkg_resources の既存のユーザーのための 移行ガイド があります。

概要

例えば、pip を使ってインストールした 配布パッケージ のバージョン文字列を取得したいとします。 まず、仮想環境を作成し、そこに何かをインストールすることから始めましょう:

$ python -m venv example
$ source example/bin/activate
(example) $ python -m pip install wheel

以下のように実行することで、wheel のバージョン文字列を取得することができます:

(example) $ python
>>> from importlib.metadata import version  
>>> version('wheel')  
'0.32.3'

また、 console_scriptsdistutils.commands などのエントリポイントのプロパティ(通常は 'group' や 'name' )で選択可能なエントリポイントの集合を取得することができます。 各グループは エントリポイント オブジェクトの集合を含んでいます。

ディストリビューションのメタデータ を取得することができます。:

>>> list(metadata('wheel'))  
['Metadata-Version', 'Name', 'Version', 'Summary', 'Home-page', 'Author', 'Author-email', 'Maintainer', 'Maintainer-email', 'License', 'Project-URL', 'Project-URL', 'Project-URL', 'Keywords', 'Platform', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Requires-Python', 'Provides-Extra', 'Requires-Dist', 'Requires-Dist']

また、 配布物のバージョン番号 を取得し、 構成ファイル をリストアップし、配布物の 配布物の要件 のリストを取得することができます。

機能 API

本パッケージは、公開APIを通じて以下の機能を提供します。

エントリポイント

entry_points() 関数は、エントリポイントの集合を返します。各 EntryPoint.name, .group, .value 属性と値を解決する .load() メソッドを持っています。 また、 .value 属性の構成要素を取得するための .module, .attr, .extras 属性が存在します。

すべてのエントリポイントに問い合わせる:

>>> eps = entry_points()  

entry_points() 関数は、すべての EntryPoint オブジェクトを集めた EntryPoints オブジェクトを、便宜上 namesgroups 属性を付けて返します。

>>> sorted(eps.groups)  
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']

EntryPoints には、特定のプロパティに一致するエントリポイントを選択するための select メソッドがあります。console_scripts グループ内のエントリポイントを選択する:

>>> scripts = eps.select(group='console_scripts')  

Equivalently, since entry_points passes keyword arguments through to select:

>>> scripts = entry_points(group='console_scripts')  

"wheel" という名前の特定のスクリプトを選択します。(wheelプロジェクトにあります):

>>> 'wheel' in scripts.names  
True
>>> wheel = scripts['wheel']  

同様に、選択時にそのエントリポイントを問い合わせます:

>>> (wheel,) = entry_points(group='console_scripts', name='wheel')  
>>> (wheel,) = entry_points().select(group='console_scripts', name='wheel')  

解決したエントリポイントを検証する:

>>> wheel  
EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')
>>> wheel.module  
'wheel.cli'
>>> wheel.attr  
'main'
>>> wheel.extras  
[]
>>> main = wheel.load()  
>>> main  
<function main at 0x103528488>

groupname はパッケージの作者によって定義された任意の値で、通常クライアントは特定のグループのエントリポイントを解決したいと思うでしょう。エントリポイント、その他の定義、使用方法についての詳細は setuptoolsのドキュメント を参照してください。

Compatibility Note

The "selectable" entry points were introduced in importlib_metadata 3.6 and Python 3.10. Prior to those changes, entry_points accepted no parameters and always returned a dictionary of entry points, keyed by group. With importlib_metadata 5.0 and Python 3.12, entry_points always returns an EntryPoints object. See backports.entry_points_selectable for compatibility options.

配布物メタデータ

すべての 配布パッケージ にはメタデータが含まれており、 metadata() 関数を使って取得することができます:

>>> wheel_metadata = metadata('wheel')  

返されたデータ構造である PackageMetadata のキーはメタデータのキーワードを表し、値は配布パッケージのメタデータから解析されずに返されます:

>>> wheel_metadata['Requires-Python']  
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'

PackageMetadata には json 属性があり、 PEP 566 に従ってすべてのメタデータをJSON互換の形式で返します:

>>> wheel_metadata.json['requires_python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'

注釈

metadata() が返すオブジェクトの実際の型は実装の詳細であり、 PackageMetadataプロトコル が示すインターフェースを通じてのみアクセスすることができます。

バージョン 3.10 で変更: ペイロードを通して提示されるとき、 Description がメタデータに含まれるようになりました。行の継続文字は削除されました。

json 属性が追加されました。

配布物バージョン

version() 関数は 配布パッケージ のバージョン番号を文字列で取得するもっとも簡単な方法です。:

>>> version('wheel')  
'0.32.3'

配布物ファイル

また、配布パッケージに含まれるファイルのフルセットを取得することもできます。files() 関数は 配布パッケージ 名を受け取り、この配布パッケージにインストールされているすべてのファイルを返します。返される各ファイルオブジェクトは PackagePath で、 pathlib.PurePath から派生したオブジェクトに、メタデータで示された dist, size, hash プロパティを追加しています。 例えば:

>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0]  
>>> util  
PackagePath('wheel/util.py')
>>> util.size  
859
>>> util.dist  
<importlib.metadata._hooks.PathDistribution object at 0x101e0cef0>
>>> util.hash  
<FileHash mode: sha256 value: bYkw5oMccfazVCoYQwKkkemoVyMAFoR34mmKBx8R1NI>

ファイルを取得したら、その内容を読むこともできます:

>>> print(util.read_text())  
import base64
import sys
...
def as_bytes(s):
    if isinstance(s, text_type):
        return s.encode('utf-8')
    return s

また、 locate メソッドを使用すると、ファイルへの絶対パスを取得することができます:

>>> util.locate()  
PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')

In the case where the metadata file listing files (RECORD or SOURCES.txt) is missing, files() will return None. The caller may wish to wrap calls to files() in always_iterable or otherwise guard against this condition if the target distribution is not known to have the metadata present.

配布物の要件

配布パッケージ に必要なすべての要件を取得するには、 requires() 関数を使用します:

>>> requires('wheel')  
["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]

Mapping import to distribution packages

インポート可能なトップレベルのPythonモジュールまたは パッケージ を提供する 配布パッケージ 名(名前空間パッケージの場合はその名前)を解決する便利なメソッドです:

>>> packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}

Some editable installs, do not supply top-level names, and thus this function is not reliable with such installs.

Added in version 3.10.

Distributions

上記のAPIは最も一般的で便利な使い方ですが、 Distribution クラスからすべての情報を得ることができます。 Distribution はPython 配布パッケージ のメタデータを表す抽象オブジェクトです。 Distribution のインスタンスを取得することができます。

>>> from importlib.metadata import distribution  
>>> dist = distribution('wheel')  

したがって、バージョン情報を取得する別の方法として、 Distribution インスタンスを使用します:

>>> dist.version  
'0.32.3'

Distribution インスタンスには、あらゆる種類の追加メタデータが用意されています:

>>> dist.metadata['Requires-Python']  
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
>>> dist.metadata['License']  
'MIT'

利用可能なメタデータのフルセットは、ここでは説明しません。詳細は コアとなるメタデータの仕様 を参照してください。

Distribution Discovery

デフォルトでは、このパッケージは組み込みで、ファイルシステムおよび zip ファイル 配布パッケージ のメタデータを発見するためのサポートを提供します。このメタデータ検索のデフォルトは sys.path ですが、その値をどのように解釈するかは、他のインポート機構が行う方法とは若干異なります。具体的には:

  • importlib.metadatasys.pathbytes オブジェクトを受け入れません。

  • importlib.metadata は、インポート時には無視されますが、 sys.path 上の pathlib.Path オブジェクトを優先的に使用します。

検索アルゴリズムの拡張

Because Distribution Package metadata is not available through sys.path searches, or package loaders directly, the metadata for a distribution is found through import system finders. To find a distribution package's metadata, importlib.metadata queries the list of meta path finders on sys.meta_path.

By default importlib.metadata installs a finder for distribution packages found on the file system. This finder doesn't actually find any distributions, but it can find their metadata.

抽象クラス importlib.abc.MetaPathFinder はPythonの importシステムによってファインダーに期待されるインターフェイスを定義しています。 importlib.metadata はこのプロトコルを拡張し、 sys.meta_path からファインダーにオプションの find_distributions を呼び出すことができるようにし、この拡張インターフェースを DistributionFinder 抽象基底クラスとして提示し、この抽象メソッドを定義しています:

@abc.abstractmethod
def find_distributions(context=DistributionFinder.Context()):
    """Return an iterable of all Distribution instances capable of
    loading the metadata for packages for the indicated ``context``.
    """

DistributionFinder.Context オブジェクトは、検索するパスと一致する名前を示す .path.name のプロパティを提供し、その他の関連するコンテキストを提供することもできます。

つまり、ファイルシステム以外の場所にある配布パッケージのメタデータを見つけるには、 Distribution をサブクラス化して抽象メソッドを実装します。そして、カスタムファインダーから find_distributions() メソッドで、派生した Distribution のインスタンスを返します。