名前空間パッケージをパッケージする¶
名前空間 (Namespace) パッケージは、複数かつ個別の パッケージ (曖昧にならないようにこの文書では 配布物 と呼ぶことにする) を越えて、単一の パッケージ の中のサブパッケージやモジュールを分離できるようにすることができます。例えば、下に示すようなパッケージ構造であれば:
mynamespace/
__init__.py
subpackage_a/
__init__.py
...
subpackage_b/
__init__.py
...
module_b.py
setup.py
そして、このパッケージを自分のソースコード中で使うにはこのようにする:
from mynamespace import subpackage_a
from mynamespace import subpackage_b
そうすることで、これらのサブパッケージ群を別々のふたつの配布物に分割することができます:
mynamespace-subpackage-a/
setup.py
mynamespace/
subpackage_a/
__init__.py
mynamespace-subpackage-b/
setup.py
mynamespace/
subpackage_b/
__init__.py
module_b.py
それぞれのサブパッケージは、今や、個別にインストール・使用・バージョン管理することができます。
名前空間パッケージは、 (単独の会社から出ている複数の製品向けのクライアントライブラリの巨大な集積のような) 緩やかに関連したパッケージが多数含まれるコレクションに役立つでしょう。しかしながら、名前空間パッケージにはいくつかの注意書きがあって、全ての場合に適切と言うわけではありません。単純明快な代替策は、あなたの配布物のすべてについて import mynamespace_subpackage_a
のような接頭語を使うことです (インポートするオブジェクトの名前を短く保つために import mynamespace_subpackage_a as subpackage_a
のようにインポートすることさえできます) 。
名前空間パッケージを作成する¶
現在、名前空間パッケージを作るには3個の異なる手法があります:
組み込みの名前空間パッケージ を用いる方法。この種の名前空間パッケージは PEP 420 で定義されていて、 Python 3.3 およびそれ以降で利用することができます。パッケージ中の名前空間が Python 3 だけをサポートすればよくて
pip
でインストールするのであれば、これが推奨される方法です。pkgutil 型の名前空間パッケージ を用いる方法。 Python 2 および 3 をサポートする必要があって
pip
でもpython setup.py install
でもインストールできるようにしたいなら、これが推奨される方法です。pkg_resources 型の名前空間パッケージ を使う方法。この手法を採用した既存のパッケージとの互換性を保つ必要がある場合か、あなたのパッケージに zip 耐性を持つ必要がある場合に推奨されます。
警告
組み込みの名前空間パッケージや pkgutil 型の名前空間パッケージは多くの点で互換性がありますが、 pkg_resources 型の名前空間パッケージは他の手法とは互換性がありません。同じ名前空間向けにパッケージを提供するような複数の配布物で、異なる手法を用いることは推奨されません。
組み込みの名前空間パッケージ¶
Python 3.3 では PEP 420 から 暗黙の 名前空間パッケージを追加しました。組み込みの名前空間パッケージを作成するのに必要なことは、名前空間パッケージのディレクトリから __init__.py
を取り除くことだけです。ファイル構造の例はこちら:
setup.py
mynamespace/
# No __init__.py here.
subpackage_a/
# Sub-packages have __init__.py.
__init__.py
module.py
名前空間パッケージを用いる各配布物で __init__.py
を省くこと、または、 pkgutil 型の __init__.py
を使用することが極めて重要です。もしいずれかの配布物でこれを忘れると、名前空間の論理が破綻して、他のサブパッケージをインポートすることができなくなります。
my namespace
が __init__.py
を含まないので、 setuptools.find_packages()
はサブパッケージを検出しようとしません。代わりに setuptools.find_namespace_packages()
を使うか、または、 setup.py
にすべてのパッケージを明示的に列挙してください。例えば:
from setuptools import setup, find_namespace_packages
setup(
name='mynamespace-subpackage-a',
...
packages=find_namespace_packages(include=['mynamespace.*'])
)
ふたつの名前空間パッケージの完全な動作例は、 組み込みの名前空間パッケージの使用例プロジェクト にあります。
注釈
組み込み名前空間パッケージと pkgutil 型の名前空間パッケージは、多くの部分で互換性があるので、 Python 3 しかサポートしない配布物では組み込み名前空間パッケージを使用し、 Python 2 と Python 3 の両方をサポートしなければならない配布物では pkgutil型名前空間パッケージを使うことが可能です。
pkgutil 型名前空間パッケージ¶
Python 2.3 で pkgutil モジュールと pkgutil.extend_path()
関数が導入されました。Python 2.3+ と Python 3 の両方に互換性を持つ必要がある名前空間パッケージを宣言するのにこれが使えるかもしれません。これは、互換性のレベルが最も高くなるアプローチとして推奨されています。
pkgutil 型の名前空間パッケージを作成するには、その名前空間パッケージ用に __init__.py
ファイルを準備する必要があります:
setup.py
mynamespace/
__init__.py # Namespace package __init__.py
subpackage_a/
__init__.py # Sub-package __init__.py
module.py
名前空間パッケージ用の __init__.py
ファイルは、次に示すもの だけ を含んでいる必要があります:
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
名前空間パッケージを用いる すべての 配布物は、同一の __init__.py
を持たなければなりません。もしいずれかの配布物で異なっていれば、名前空間の論理破綻を招き、他のサブパッケージをインポートすることができなくなるでしょう。 __init__.py
に他のコードを追加しても、それはアクセスできないものとなるでしょう。
pkgutil 型の名前空間パッケージのふたつの動作例が pkgutil 型名前空間を例示するプロジェクト にあります。
pkg_resources 型名前空間パッケージ¶
Setuptools は、 pkg_resources.declare_namespace 関数と setup()
に渡す namespace_packages
引数を提供します。これらを一緒に使うことで名前空間パッケージを宣言することができます。この手法はもはや推奨されていませんが、既存の名前空間パッケージのほとんどで使われています。この手法を採用している既存の名前空間パッケージの中に新しい配布物を作成する時には、異なる手法が相互に互換ではないために既存パッケージを移植しようとすることが推奨されていないので、この手法を採用し続けることを推奨します。
pkg_resources 型名前空間パッケージを作成するには、名前空間パッケージ用の __init__.py
を準備する必要があります:
setup.py
mynamespace/
__init__.py # Namespace package __init__.py
subpackage_a/
__init__.py # Sub-package __init__.py
module.py
名前空間パッケージ用の __init__.py
ファイルは、次に示すもの だけ を含んでいる必要があります:
__import__('pkg_resources').declare_namespace(__name__)
名前空間パッケージを用いる すべての 配布物は、同一の __init__.py
を持たなければなりません。もしいずれかの配布物で異なっていれば、名前空間の論理破綻を招き、他のサブパッケージをインポートすることができなくなるでしょう。 __init__.py
に他のコードを追加しても、それはアクセスできないものとなるでしょう。
注釈
いくつかの古めの推奨では、次のような名前空間パッケージ用 __init__.py
を使うように言っています:
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
背景にあるアイデアとしては、 setuptools を使えないような稀な場合には、パッケージを pkgutil 型パッケージに切り戻したいと言うことがあるかもしれません。 pkgutil 型と pkg_resources 型の名前空間パッケージは互いに非互換なので、これは推奨できるものではありません。 setuptool が存在するか否かが問題なのであれば、パッケージとしては install_requires
を通じて setuptools に明示的に依存すると示しておくべきです。
最後に、それぞれの配布物は setup.py
の setup()
向けに namespace_packages
引数を準備しておく必要があります。例えば:
from setuptools import find_packages, setup
setup(
name='mynamespace-subpackage-a',
...
packages=find_packages()
namespace_packages=['mynamespace']
)
pkg_resources 型の名前空間パッケージの動作可能な二つの例が pkg_resources 型名前空間例示プロジェクト で見つかるはずです。