importlib.metadata -- パッケージメタデータへのアクセス¶
バージョン 3.8 で追加.
バージョン 3.10 で変更: importlib.metadata は暫定的なものではなくなりました。
ソースコード: Lib/importlib/metadata/__init__.py
importlib.metadata はインストールされた 配布パッケージ のエントリポイントやトップレベル名 (あれば、 パッケージ やモジュール) のようなメタデータへのアクセスを提供するライブラリです。Pythonのインポートシステムをベースに構築されており、このライブラリは pkg_resources の entry point API と metadata API にある同様の機能を置き換えることを目的としています。importlib.resources と共に、このパッケージは古くて効率の悪い pkg_resources パッケージを使う必要性を無くすことができます。
importlib.metadata operates on third-party distribution packages
installed into Python's site-packages directory via tools such as
pip.
Specifically, it works with distributions with discoverable
dist-info or egg-info directories,
and metadata defined by the Core metadata specifications.
重要
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_scripts や distutils.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 オブジェクトを、便宜上 names と groups 属性を付けて返します。
>>> 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>
group と name はパッケージの作者によって定義された任意の値で、通常クライアントは特定のグループのエントリポイントを解決したいと思うでしょう。エントリポイント、その他の定義、使用方法についての詳細は 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. For compatibility, if no parameters are passed to entry_points,
a SelectableGroups object is returned, implementing that dict
interface. In the future, calling entry_points with no parameters
will return an EntryPoints object. Users should rely on the selection
interface to retrieve entry points by group.
配布物メタデータ¶
すべての 配布パッケージ にはメタデータが含まれており、 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'], ...}
バージョン 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.metadataはsys.pathのbytesオブジェクトを受け入れません。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 のインスタンスを返します。