2011-04-19 5 views
1

Étant donné le code source d'un fichier Python, je souhaite détecter tous les objets importés. Par exemple, étant donné cette source:Détection des objets importés

import mymod 
from mymod2 import obj1, obj2, obj3 
from mymod3 import aobj 

Je veux:

[('mymod2', 'obj1', 'obj2', 'obj3'), ('mymod3', 'aobj')] 

Je l'ai déjà essayé regex:

r'from (?P<mod>[_\w\d]+) import (?:(?P<obj>[_\w\d]+)[,\s]?)+' 

Mais je n'obtenir le premier objet importé:

[('mymod2', 'obj1'), ('mymod3', 'aobj')] 
+4

Cela semble une mauvaise idée de le faire avec des expressions régulières. Que se passe-t-il si la déclaration d'importation s'étend sur plusieurs lignes à l'aide de la continuation de la barre oblique inversée? Ou des parenthèses? Qu'en est-il des importations au niveau des fonctions? C'est trop complexe pour être traité par les regex. –

+0

... vous avez raison! : D – rubik

Répondre

8

Un meilleur outil que reg ular expressions est le module ast fourni avec Python. Pour trouver toutes les from ... import déclarations du périmètre externe de a.py et imprimer tous les noms importés, vous pouvez utiliser

import ast 
code = open("a.py").read() 
for node in ast.parse(code).body: 
    if isinstance(node, ast.ImportFrom): 
     for name in node.names: 
      print name.name 

Notez que ce code simple manquera toutes les déclarations qui ne sont pas directement au niveau du module, comme les déclarations d'importation à l'intérieur d'un try-block. Cela peut facilement être corrigé en utilisant ast.walk() pour parcourir tous les nœuds.

+0

+1 ast est un excellent outil. –

+0

Wow, ast est génial! – rubik

2

C'est une mauvaise idée de traiter textuellement la source Python en utilisant des regex. Une meilleure idée (sans dépendances) est de l'inclure dans votre script, puis introspecte en utilisant Python:

#-- test.py (the file you're targeting) 
from time import asctime 
from re import match, search 

#-- now to find its imports 
>>> import test 
>>> for imprt in dir(test): 
... imprt = getattr(test, imprt, None) 
... if not getattr(imprt, '__module__', None): 
...  continue 
... if imprt.__module__ in result: 
...  result[imprt.__module__].append(imprt.__name__) 
... else: 
...  result[imprt.__module__] = [imprt.__name__] 
... 
>>> result 
{'re': ['match', 'search'], 'time': ['asctime']} 
+0

Oui, mais je préférerais éviter d'exécuter le module, alors j'ai pensé pouvoir analyser le code. – rubik

Questions connexes