別のモジュールのサブディレクトリに実際にあるPythonモジュールをインポートできるようにしたいと思います。
プラグインを使ったフレームワークを開発しています。数千(現在はすでに250を超える)が予想され、1000を超えるファイルを含む1つの大きなディレクトリは必要ないため、このようなディレクトリで並べ替えて、名前の最初の文字でグループ化します。 :
framework\
__init__.py
framework.py
tools.py
plugins\
__init__.py
a\
__init__.py
atlas.py
...
b\
__init__.py
binary.py
...
c\
__init__.py
cmake.py
...
他のプラグインの開発者や、自分ほど多くのプラグインを必要としない人に負担をかけたくないので、各プラグインを「framework.plugins」名前空間に配置したいと思います。このように、プライベートプラグインの束を追加する人は、それらをframework.pluginsフォルダーに追加するだけで追加でき、次の内容__init__.py
を含むファイルが提供されます。
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
ただし、現在、この設定により、azサブディレクトリも使用するように強制されています。プラグインが別のプラグインを拡張していることがあるので、今は
from framework.plugins.a import atlas
と私はしたい
from framework.pugins import atlas
フルネームスペース名が実際にはフォルダー構造にマップされない名前空間を宣言する方法はありますか?
私はpkg_resourcesパッケージを知っていますが、これはsetuptoolsを介してのみ利用可能であり、余分な依存関係はありません。
import pkg_resources
pkg_resources.declare_namespace(__name__)
ソリューションはPython2.4-2.7.3で動作するはずです
更新:提供された回答を組み合わせて、プラグインからインポートされたすべてのプラグインのリストを取得しようとしました__init__.py
。ただし、これは依存関係のために失敗します。'c'フォルダー内のプラグインは、' t'で始まるプラグインをインポートしようとしますが、これはまだ追加されていません。
plugins = [ x[0].find_module(x[1]).load_module(x[1]) for x in pkgutil.walk_packages([ os.path.join(framework.plugins.__path__[0], chr(y)) for y in xrange(ord('a'), ord('z') + 1) ],'framework.plugins.' ) ]
私がここで正しい方向に進んでいるのか、それとも単に物事を複雑にしすぎて、自分のPEP302インポーターを作成したほうがよいのかわかりません。しかし、これらがどのように機能するかについての適切な例を見つけることができないようです。
__getattr__
更新:関数を自分でラップするという提案に従おうとしました__init__.py
が、これは役に立たないようです。
import pkgutil
import os
import sys
plugins = [x[1] for x in pkgutil.walk_packages([ os.path.join(__path__[0], chr(y)) for y in xrange(ord('a'), ord('z') + 1) ] )]
import types
class MyWrapper(types.ModuleType):
def __init__(self, wrapped):
self.wrapped = wrapped
def __getattr__(self, name):
if name in plugins:
askedattr = name[0] + '.' + name
else:
askedattr = name
attr = getattr(self.wrapped, askedattr)
return attr
sys.modules[__name__] = MyWrapper(sys.modules[__name__])