2016-08-31 5 views
0

Ich versuche, alle Funktionen in jedem gefundenen Modul aufzulisten, um das Schreiben von Testfällen zu erzwingen. Allerdings habe ich Probleme, dies nur mit dem vollständigen Pfad zur Datei als String zu tun und nicht zu importieren. Wenn ich inspect.getmembers(fullpath, inspect.isfunction) verwende, wird ein leeres Array zurückgegeben. Gibt es einen Weg, dies zu erreichen? Hier ist mein Code so weit:Listet alle Funktionen in einem Modul mit vollem Pfad auf

import glob 
import os 
import inspect 

def count_tests(moduletestdict): 
    for key,value in moduletestdict.items(): 
     print("Key: {}".format(key)) 
     print(inspect.getmembers(key, inspect.isfunction)) 

def find_functions(base_dir): 
    """moduletestdict has key value pairs where the key is the module 
    to be tested and the value is the testing module""" 
    moduletestdict = {} 
    for roots, dirs, files in os.walk(base_dir): 
     for f in files: 
      if (".py" in f) and (".pyc" not in f) and ("test_" not in f) and (f != "__init__.py"): 
       if "test_{}".format(f) in files: 
        moduletestdict["{}/{}".format(roots,f)] = "{}/{}".format(roots, "test_{}".format(f)) 
       else: 
        moduletestdict["{}/{}".format(roots,f)] = "NOTEST" 
    return moduletestdict 

if __name__ == "__main__": 
    base_dir = "/Users/MyName/Documents/Work/MyWork/local-dev/sns" 
    moduletestdict = find_functions(base_dir) 
    count_tests(moduletestdict) 

Antwort

0

brauchen Sie die Module irgendwie zu importieren, aber die „empfehlenswert“ Art und Weise ist ein bisschen schwierig, da die Dinge immer mit neuen Versionen von Python zu ändern, this answer sehen.

Hier ist ein Beispiel auf der Testläufer des gorilla library basiert, die mit Python 2 und Python 3 kompatibel:

import inspect 
import os 
import sys 


def module_iterator(directory, package_dotted_path): 
    paths = os.listdir(directory) 
    for path in paths: 
     full_path = os.path.join(directory, path) 
     basename, tail = os.path.splitext(path) 
     if basename == '__init__': 
      dotted_path = package_dotted_path 
     elif package_dotted_path: 
      dotted_path = "%s.%s" % (package_dotted_path, basename) 
     else: 
      dotted_path = basename 

     if os.path.isfile(full_path): 
      if tail != '.py': 
       continue 

      __import__(dotted_path) 
      module = sys.modules[dotted_path] 
      yield module 
     elif os.path.isdir(full_path): 
      if not os.path.isfile(os.path.join(full_path, '__init__.py')): 
       continue 

      __import__(dotted_path) 
      package = sys.modules[dotted_path] 
      yield package 
      for module in module_iterator(full_path, dotted_path): 
       yield module 

def main(): 
    directory_path = '/path/to/your/package' 
    package_name = 'package' 
    sys.path.insert(0, directory_path) 
    modules = module_iterator(directory_path, package_name) 
    for module in modules: 
     functions = inspect.getmembers(module, inspect.isfunction) 
     print("functions for module '{0}': {1}".format(
      module.__name__, functions) 
     ) 

if __name__ == "__main__": 
    main() 

Hier /path/to/your/package wäre das Repository in das Paket, dass das Verzeichnis ist in der Readme enthält, die Dokumente usw., wie es bei Pythons Paketen häufig der Fall ist, und package_name wäre der Verzeichnisname innerhalb des Repositorys, der die Root-Datei __init__.py enthält.

Tatsächlich akzeptiert die Funktion module_iterator auch ein Modul für ihren Parameter package_dotted_path, wie zum Beispiel 'package.subpackage.module', aber dann werden nur die Funktionen von diesem spezifischen Modul abgerufen. Wenn stattdessen ein Paket übergeben wird, werden alle rekursiv verschachtelten Module überprüft.

+0

Nur um klar zu sein, erwartet 'package_dotted_path' den Namen des Moduls mit der' .py' Dateierweiterung, richtig? – asdf

+0

Ich habe meine Antwort bearbeitet (und korrigiert), um das Problem zu beheben. Grundsätzlich muss der 'package_dotted_path', den Sie an die Funktion übergeben, der Paketname sein, der alle Ihre Module enthält. Zum Beispiel könnte es einfach "Paket" oder "Paket-Paket" oder sogar direkt ein Modul wie "Paket-Paket-Modul" sein. Die einzige Bedingung ist, dass ein solcher gepunkteter Pfad importiert werden muss. Dies wird hier sichergestellt, indem das übergeordnete Verzeichnis des Root-Pakets zu "sys.path" hinzugefügt wird. – ChristopherC

Verwandte Themen