2011-11-09 9 views
0

一般的に私のプロジェクトのコードが実際に大きなフレームワークからどのようなコードを使用しているのかを理解したいと思います。Pythonプロジェクトのインポートを分析する

まず、すべてのインポート(静的分析の可能性があります)と、可能であればこれらのインポートのうちのどれが実際に使用されているかを知りたいと思います。

最初の問題については、もちろん正規表現を使用できますが、よりクリーンな方法を探したいと思います。 しかし、私はast/inspect/parserでどのように見えません。

2番目の問題については、輸入の一部が実際には使用されていない場合に自動的に見つかるはずですが、どうしたらいいですか?

EDIT: おそらく最も良い方法は、インポートされたすべてを記録し、次にデフォルトのインポートメカニズムを呼び出す単純なインポートフックです。

class MyLoader(object): 
""" 
Loader object 
""" 

def __init__(self): 
    self.loaded = set() 

def find_module(self, module_name, package=None): 
    print("requesting %s" % module_name) 
    self.loaded.add(module_name) 
    return self 

def load_module(self, fullname): 
    fp, pathname, stuff = imp.find_module(fullname) 
    imp.load_module(fullname, fp, pathname, stuff) 

しかし、「ランダム」私は 将来からの輸入部門 はImportErrorを取得インポートしようとしている:いいえモジュールの名前将来、私は手段を考える

は、だから私のような何かを試してみました私は何かが欠けている.. 私はいくつかのインポートイントロスペクション、任意のヒントを行うためにimpを使用する任意の簡単な例を発見していない?

答えて

1

このような分析の問題は、Pythonの動的な性質になります。実際、使用されるモジュールのセットは、ランタイム変数に依存してもよい(すなわち、いくつかのモジュールは、特定のランタイム条件の下でのみインポートされ、使用される)。

が最善の方法ではないかもしれないが、あなたのコードのためのかなりまともなテストカバレッジを持っている場合は、テスト実行時にロードされたかのモジュールをチェックするcoverage.py出力を使用することができます。

+0

必ずはい、本当に静的解析は非常にうまく機能しません何が起こるかの明確な見解を持っています。しかし、Pylintはかなり良い仕事をしていますが、私はそれがコードの重い構文解析仕事をしていると思います。 輸入者プロトコルでの私の試みについては、上記を参照してください。 –

1

輸入品の一覧表示は実際には非常に簡単です。

私はfind_moduleがNoneを返す場合、それは単に次のにフォールバックします(PEP 302によって定義される)輸入プロトコルの最小限の実装を必要とします。

この簡単なスクリプトは、実際に渡されたプログラムによって行わ輸入を表示することができます。これを考えると

import sys 

class ImportInspector(object): 

    def find_module(self, module, path): 
     print("importing module %s" % module) 


if __name__ == '__main__': 
    progname = sys.argv[0] 
    # shift by one position 
    sys.argv = sys.argv[1:] 
    sys.meta_path.append(ImportInspector()) 

    code = compile(open(progname, 'rb').read(), progname, 'exec') 
    exec(code) 

は、トリックの任意の種類は、それの上に実装することができます。 たとえば、セット内のインポートを追跡し、プログラムが終了するとそのすべてを格納することができます。

私は、私たちも、輸入のhiearchyを取得し、gprof2dotが何と同様のグラフを生成かもしれないと思うが、唯一の輸入品の分析に基づきます。

0

別の質問を開く必要があるかどうかはわかりませんが、私はここに従おうとします。

これで、もっと面白いことをしたいと思っていました。私のコードを解析するためにシーンの後ろに汚い仕事をするコンテキストマネージャーを書いてください。

以下のコードは、私が本当に理解することはできません非常に奇妙なエラーを与える:

File "study_imports.py", line 59, in <module> 
    exec(code) 
File "study_imports.py", line 55, in <module> 
    cl = CollectImports() 
File "study_imports.py", line 15, in __init__ 
    self.loaded = set() 
RuntimeError: maximum recursion depth exceeded while calling a Python object 

import os 
import sys 

class CollectImports(object): 
    """ 
    Import hook, adds each import request to the loaded set and dumps 
    them to file 
    """ 

    def __init__(self): 
     self.loaded = set() 

    def __str__(self): 
     return str(self.loaded) 

    def dump_to_file(self, fname): 
     """Dump the loaded set to file 
     """ 
     dumped_str = '\n'.join(x for x in self.loaded) 
     open(fname, 'w').write(dumped_str) 

    def find_module(self, module_name, package=None): 
     self.loaded.add(module_name) 


class CollectorContext(object): 
    """Example of context manager to collect and dump on exit 
    XXX: not working at the moment 
    """ 

    def __init__(self, collector, argv, output_file): 
     self.collector = collector 
     self.argv = argv 
     self.output_file = output_file 

    def __enter__(self): 
     self.argv = self.argv[1:] 
     sys.meta_path.append(self.collector) 

    def __exit__(self, type, value, traceback): 
     # TODO: should assert that the variables are None, otherwise 
     # we are quitting with some exceptions 
     self.collector.dump_to_file(self.output_file) 
     sys.meta_path.remove(self.collector) 



if __name__ == '__main__': 
    # main() 
    progname = sys.argv[0] 
    cl = CollectImports() 

    with CollectorContext(cl, sys.argv, 'imports.log'): 
     code = compile(open(progname).read(), progname, 'exec') 
     exec(code) 
関連する問題