pipで指定する名前とimport文の名前は、必ずしも同じではない。インストールした配布パッケージの情報はimportlib.metadata、実際に読み込むモジュールの場所はimportlib.utilやモジュール自身から調べられる。対応する名前、版、配置を分けて確認すれば、名前の取り違えと環境の取り違えを切り分けやすい。
配布名とimport名の役割を分ける
配布パッケージはpipが導入やバージョン管理に使う単位である。一方、importパッケージやモジュールはPythonコードから読み込む単位である。一つの配布物に複数のimport名が含まれる場合もあり、名前空間パッケージでは一つのimport名に複数の配布物が関係することもある。
そのため、import名から配布名を単純な文字列置換で推測しない方がよい。ハイフンとアンダースコアの違いだけとは限らず、importしたオブジェクトの__version__が常に存在するわけでもない。パッケージの公式案内とインストール済みメタデータの両方を使う。
対応名とバージョンを確認する
次の例では、配布名tip-distribution、import名tipmodという練習用パッケージを通常インストールしている。一般公開の同名パッケージを取得する例ではなく、名前の違いを確かめるためのローカル配布物である。
inspect_package.py
from importlib import metadata, util
from pathlib import Path
import_name = "tipmod"
names = sorted(metadata.packages_distributions().get(import_name, []))
print("distributions:", names)
assert names == ["tip-distribution"]
for name in names:
dist = metadata.distribution(name)
print("metadata:", dist.metadata["Name"], dist.version)
assert dist.version == "0.1.0"
spec = util.find_spec(import_name)
assert spec is not None and spec.origin is not None
origin = Path(spec.origin)
print("module:", origin.parent.name + "/" + origin.name)
try:
metadata.version("tip-no-such-distribution-2026")
except metadata.PackageNotFoundError:
print("missing distribution: PackageNotFoundError")
else:
raise AssertionError("The practice distribution must not exist")
実行結果
distributions: ['tip-distribution']
metadata: tip-distribution 0.1.0
module: tipmod/__init__.py
missing distribution: PackageNotFoundError
packages_distributions()の値は一覧であり、一つの文字列ではない。対応が得られた配布名ごとにdistribution()でメタデータを読み、Nameとversionを確認している。表示を安定させるため、配布名の一覧だけsorted()で並べている。
バージョンと実際の読み込み元を照合する
metadataが返す版は、現在のPythonから見える配布メタデータの版である。作業フォルダーに同名モジュールがある場合などは、メタデータと実際にimportするコードが一致しないこともある。版の確認だけでなく、find_specのoriginや読み込み後の__file__も照合したい。
掲載例では実機依存のパスを出さないよう、originの末尾と親フォルダーだけを表示している。実際の診断では元のorigin全文を手元で確認する。distributionのlocate_file(“”)から配布物の基準位置も調べられるが、読み込まれるモジュールの一意な場所と常に同じ意味になるわけではない。
見つからない場合を区別する
versionやdistributionへ渡した配布名が見つからないと、PackageNotFoundErrorになる。import名を渡してしまっただけなのか、本当にその環境へ導入されていないのかを区別する必要がある。失敗するプログラムのsys.executableから始め、同じPythonのpipで調べよう。
一方、標準ライブラリは通常、pipで管理する第三者配布パッケージではない。jsonのimportが成功しても、同じ名前の配布メタデータが見つかるとは限らない。メタデータがないことだけを理由に、標準ライブラリを追加インストールしようとしないことが大切である。
対応表が完全とは限らない
packages_distributionsは、利用可能なメタデータなどからトップレベルの対応を調べる補助である。特に一部のeditable installでは、必要な情報が十分でなく対応が得られない場合がある。空の一覧になったら、そのimport名が絶対に存在しないと断定せず、導入方法と公式の配布名を確認する。
また、環境内に古いメタデータや複数の配置が残ると、情報が分かりにくくなる。診断のためにsite-packages内のファイルを手作業で削るより、新しいvenvに必要なものだけを導入して比較する方が、変更の影響を限定しやすい。
問い合わせには必要な情報をそろえる
不具合を調べるときは、Python本体の版、配布名と版、実行ファイル、実際のモジュールの読み込み元を一組として記録する。これにエラー全文と最小の再現コードがあれば、単に「インストールした」という説明より環境の違いを追いやすい。
ただしパスにはユーザー名や社内のプロジェクト名が含まれる場合がある。外部へ共有する際には個人情報を伏せ、どのvenvとどのsite-packagesを指すかが分かる範囲を残す。配布名・import名・版・位置の四つを区別することが、診断の基本になる。
動作確認と参考資料
掲載例はLinux・CPython 3.12.14で動作確認した。OS固有のコマンドや環境ごとに変わるパスは、本文中の条件を確認して使ってほしい。
関連するTips
- pipで入れたのにimportできないときのトラブルシューティング
- 実行中のPythonとインストール先の食い違いを診断する
- 自作ライブラリを別プロジェクトから使う:editable installの始め方
