support loadingg module files with multiple classes
[tests.git] / qaapi / qa / QAAPI.py
1 import sys, os
2 import traceback
3 import qa.modules
4 from qa.Config import Config
5 from qa.logger import log       
6
7 class QAAPI:
8    
9     modules_path = os.path.realpath(qa.modules.__path__[0])
10     methods = []
11                 
12         
13     def __init__(self, globals, config = None, logging=None, verbose=None):
14         if config is None: self.config = Config()
15         else: self.config = Config(config)
16
17         module_files = self.module_files(self.modules_path)
18         callables = set()
19         # determine what is callable
20         for file in module_files:
21             callables.update(self.callables(file))
22                 
23         # Add methods to self and global environemt     
24         for method in callables:            
25             if logging: method = log(method, method.mod_name)
26             elif hasattr(self.config, 'log') and self.config.log:
27                 method = log(method, method.mod_name)
28            
29             class Dummy: pass
30             paths = method.mod_name.split(".")
31             print dir(method)
32             
33             if len(paths) > 1:
34                 first = paths.pop(0)
35
36                 if not hasattr(self, first):
37                     obj = Dummy()
38                     setattr(self, first, obj)
39                     # Also add to global environment if specified
40                     if globals is not None:
41                         globals[first] = obj
42
43                 obj = getattr(self, first)
44
45                 for path in paths:
46                     if not hasattr(obj, path):
47                         if path == paths[-1]:
48                             setattr(obj, path, method)
49                             globals[method.mod_name]=obj  
50                         else:
51                             setattr(obj, path, Dummy())
52                     obj = getattr(obj, path)
53             else:
54                 if globals is not None:
55                     globals[method.mod_name] = method           
56
57     def module_files(self, module_dir):
58         """
59         Build a list of files   
60         """     
61         
62         # Load files from modules direcotry
63         real_files = lambda name: not name.startswith('__init__') \
64                                   and  name.endswith('.py')
65         remove_ext = lambda name: name.split(".py")[0]
66         iterator = os.walk(module_dir)
67         (root, basenames, files) = iterator.next()
68         module_base = ""
69         module_files = []
70         module_files.extend([method_base+file for file in map(remove_ext, filter(real_files, files))])
71
72         # recurse through directory             
73         for (root, dirs, files) in iterator:
74             parts = root.split(os.sep)
75             for basename in basenames:
76                 if basename in parts:
77                     module_base = ".".join(parts[parts.index(basename):])+"."
78             files = filter(real_files, files)
79             files = map(remove_ext, files)
80             module_files.extend([module_base+file for file in  files])
81
82         return module_files 
83
84     def callables(self, module_file):
85         """
86         Return a new instance of the specified method. 
87         """      
88         
89         # Get new instance of method
90         parts = module_file.split(".")
91         # add every part except for the last to name (filename)
92         module_dir =  "qa.modules."
93         module_basename = ".".join(parts[:-1])
94         module_path = module_dir + module_file
95         try:
96             module = __import__(module_path, globals(), locals(), module_path)
97             callables = []
98
99             for attribute in dir(module):
100                 attr = getattr(module, attribute)
101                 if callable(attr):
102                     setattr(attr, 'mod_name', module_basename+"."+attribute)
103                     callables.append(attr(self.config))
104             return callables 
105         except ImportError, AttributeError:
106             raise  
107          
108