利用可能なモジュール一覧を取得する
ふとPythonで利用可能なモジュールの一覧を取得したくなったのでメモ。
条件
ここでいう利用可能なモジュール および パッケージ一覧とは、以下のようなものとする。
- ビルトインで組み込まれてるやつ
- site-packages にインストールされてるやつ
- virtualenvなどの仮想環境などにインストールされてるやつ
- というかパスが通ってて、モジュール、パッケージとして認識されるヤツ全て
- 確認したいのじゃなくてリストとかのデータとして扱いたい
こんなん僕が求めてるのとちゃう
求めてるものとはなんか違った夢の残骸達
sys.builtin_module_names
文字通り、ビルトインで入ってるやつの一覧。足りない
import sys print sys.builtin_module_names #=> ('__builtin__', '__main__', '_ast', '_codecs', '_sre', '_symtable', '_warnings', '_weakref', 'errno', 'exceptions', 'gc', 'imp', 'marshal', 'posix', 'pwd', 'signal', 'sys', 'thread', 'xxsubtype', 'zipimport')
sys.modules
実行時にロード済みなやつの一覧。まだ足りない。とういかロードしてない組み込みのヤツは出てこない。
import sys print sys.modules.keys() #=>['cStringIO', 'copy_reg', 'encodings', 'site', '__builtin__', '__main__', 'encodings.encodings', 'abc', 'posixpath', 'flaskext', '_weakrefset', 'errno', 'pprint', 'encodings.codecs', '_abcoll', 'types', '_codecs', 'new', '_warnings', 'genericpath', 'stat', 'zipimport', 'encodings.__builtin__', 'warnings', 'UserDict', 'encodings.utf_8', 'sys', 'codecs', 'os.path', 'signal', 'linecache', 'posix', 'encodings.aliases', 'exceptions', 'os', '_weakref']
help('modules')
めっさ一杯出た。大分近い。仮想環境にいれたヤツとかもちゃんと拾ってくれてる。。。けど結果が標準出力されるのでなんか微妙
$ python -c "help('modules')" Please wait a moment while I gather a list of all available modules... ArgImagePlugin _Mlte difflib pimp Audio_mac _MozillaCookieJar dir_help pip BaseHTTPServer _OSA dircache pipes Bastion _Qd dis pkg_resources BdfFontFile _Qdoffs distutils pkgutil BeautifulSoup _Qt django_assets platform BeautifulSoupTests _Res doctest plistlib BmpImagePlugin _Scrap dprint popen2 ... ...
これや僕が求めてたのはこれなんや
「python -c "help('modules')"」の結果は、「pydoc modules」と等価である。というかhelpは多分pydocを見てる。というわけで、pydoc.pyをあら探しする。
であった。それが「pydoc.ModuleScanner」とかいうヤツ。pydoc.pyではこんな使いかたしてた。
1879 modules = {} 1880 def callback(path, modname, desc, modules=modules): 1881 if modname and modname[-9:] == '.__init__': 1882 modname = modname[:-9] + ' (package)' 1883 if find(modname, '.') < 0: 1884 modules[modname] = 1 1885 def onerror(modname): 1886 callback(None, modname, None) 1887 ModuleScanner().run(callback, onerror=onerror) 1888 self.list(modules.keys())
これを使って「pydoc modules」は実現されていた。単純に一覧が欲しいだけので、コピってこんな感じに変えてみた。
#!/usr/bin/env python # -*- coding: utf-8 -* from pydoc import ModuleScanner from string import find modules = [] def callback(path, modname, desc, modules=modules): if modname and modname[-9:] == '.__init__': modname = modname[:-9] if find(modname, '.') < 0 and modname not in modules: modules.append(modname) def onerror(modname): callback(None, modname, None) ModuleScanner().run(callback, onerror=onerror) print modules
これを実行すると。。。
$ python all_modules.py ['__builtin__', '_ast', '_codecs', '_sre', '_symtable', '_warnings', '_weakref', 'errno', 'exceptions', 'gc', 'imp', 'marshal', 'posix', 'pwd', 'signal', 'sys', 'thread', 'xxsubtype', 'zipimport', 'all_avaliable_modules', 'all_avaliable_modules2', 'ascii_to_ebcidic', 'blinker_sample', 'bool_judge', 'cast', 'class_name', 'converting_byte', 'datetime_test', 'dict_key_map', 'dict_merge', 'diff_time', 'dir_help', 'dprint', 'fib', 'file_abs_path', 'fold_test', 'func_args_disruptiv ... ...
おー。いっぱいでてきた。ビルトインも、仮想環境も、カレントディレクトリのヤツも全部出てきたw
サブモジュール、パッケージも一覧に含める
上のヤツでは、トップレベル(と呼んでいいんだろうか?)のパッケージとモジュールの一覧しか表示されないようになってる。サブモジュール・パッケージも含めて一覧で表示したかったら。「callback」関数をこう変えればいい。
def callback(path, modname, desc, modules=modules): if modname and modname[-9:] == '.__init__': modname = modname[:-9] - if find(modname, '.') < 0 and modname not in modules: - modules.append(modname) + if modname not in modules: + modules.append(modname)
愚行
ModuleScannerに辿り着く前は、もういいやって気分で「pydoc modules」の標準出力をパースして強引にリストを取得しようとしている愚かな僕がいました。けど「sys.path.insert」で追加したパスのモジュールとか取得できないじゃんとか思ってやめた
#!/usr/bin/env python # -*- coding: utf-8 -*- import pprint import commands import re ret = commands.getoutput('python -c "help(\'modules\')"') module_list = [] start = False for line in ret.split('\n'): if re.match(r'[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]+[^ ]+$', line): start = True if start and line == '': break if not start: continue line = re.sub(r'[ ]+',r' ', line) for module in line.split(' '): if module.strip(' ') != '': module_list.append(module.strip(' ')) module_list.sort() pprint.pprint(module_list)
追記(2015/3/4)
コメント欄で 教えて貰った「pkgutil.iter_modules」を使うとインストール済みのやつとかを一覧でみることができるようです。いい感じですね。:id:hirokiky さんありがとうございます。
>>> import pkgutil >>> for m in pkgutil.iter_modules(): ... print m ... (<pkgutil.ImpImporter instance at 0x103103e18>, 'UserDict', False) (<pkgutil.ImpImporter instance at 0x103103e18>, '_abcoll', False) (<pkgutil.ImpImporter instance at 0x103103e18>, '_weakrefset', False) (<pkgutil.ImpImporter instance at 0x103103e18>, 'abc', False) (<pkgutil.ImpImporter instance at 0x103103e18>, 'codecs', False)
余談
- ModuleScannerのonerrorという関数は、何かしらのエラーでimportできないパッケージに対して呼び出される。(モジュールではなく)