control_data.py revision 3abbceee9421805bed8f5c2c6c6abb9299b32cbf
1# 2# Copyright 2008 Google Inc. Released under the GPL v2 3 4import compiler, textwrap, types 5 6 7REQUIRED_VARS = set(['author', 'doc', 'name', 'time', 'test_class', 8 'test_category', 'test_type']) 9 10class ControlVariableException(Exception): 11 pass 12 13 14class ControlData(object): 15 def __init__(self, vars, path, raise_warnings=False): 16 # Defaults 17 self.path = path 18 self.dependencies = set() 19 self.experimental = False 20 self.run_verify = True 21 self.sync_count = 1 22 23 diff = REQUIRED_VARS - set(vars) 24 if len(diff) > 0: 25 warning = ("WARNING: Not all required control " 26 "variables were specified in %s. Please define " 27 "%s.") % (self.path, ', '.join(diff)) 28 if raise_warnings: 29 raise ControlVariableException(warning) 30 print textwrap.wrap(warning, 80) 31 32 for key, val in vars.iteritems(): 33 try: 34 self.set_attr(key, val, raise_warnings) 35 except Exception, e: 36 if raise_warnings: 37 raise 38 print "WARNING: %s; skipping" % e 39 40 41 def set_attr(self, attr, val, raise_warnings=False): 42 attr = attr.lower() 43 try: 44 set_fn = getattr(self, 'set_%s' % attr) 45 set_fn(val) 46 except AttributeError: 47 # This must not be a variable we care about 48 pass 49 50 51 def _set_string(self, attr, val): 52 val = str(val) 53 setattr(self, attr, val) 54 55 56 def _set_option(self, attr, val, options): 57 val = str(val) 58 if val.lower() not in [x.lower() for x in options]: 59 raise ValueError("%s must be one of the following " 60 "options: %s" % (attr, 61 ', '.join(options))) 62 setattr(self, attr, val) 63 64 65 def _set_bool(self, attr, val): 66 val = str(val).lower() 67 if val == "false": 68 val = False 69 elif val == "true": 70 val = True 71 else: 72 msg = "%s must be either true or false" % attr 73 raise ValueError(msg) 74 setattr(self, attr, val) 75 76 77 def _set_int(self, attr, val, min=None, max=None): 78 val = int(val) 79 if min is not None and min > val: 80 raise ValueError("%s is %d, which is below the " 81 "minimum of %d" % (attr, val, min)) 82 if max is not None and max < val: 83 raise ValueError("%s is %d, which is above the " 84 "maximum of %d" % (attr, val, max)) 85 setattr(self, attr, val) 86 87 88 def _set_set(self, attr, val): 89 val = str(val) 90 items = [x.strip() for x in val.split(',')] 91 setattr(self, attr, set(items)) 92 93 94 def set_author(self, val): 95 self._set_string('author', val) 96 97 98 def set_dependencies(self, val): 99 self._set_set('dependencies', val) 100 101 102 def set_doc(self, val): 103 self._set_string('doc', val) 104 105 106 def set_experimental(self, val): 107 self._set_bool('experimental', val) 108 109 110 def set_name(self, val): 111 self._set_string('name', val) 112 113 114 def set_run_verify(self, val): 115 self._set_bool('run_verify', val) 116 117 118 def set_sync_count(self, val): 119 self._set_int('sync_count', val, min=1) 120 121 122 def set_time(self, val): 123 self._set_option('time', val, ['short', 'medium', 'long']) 124 125 126 def set_test_class(self, val): 127 self._set_string('test_class', val.lower()) 128 129 130 def set_test_category(self, val): 131 self._set_string('test_category', val.lower()) 132 133 134 def set_test_type(self, val): 135 self._set_option('test_type', val, ['client', 'server']) 136 137 138def _extract_const(n): 139 assert(n.__class__ == compiler.ast.Assign) 140 assert(n.expr.__class__ == compiler.ast.Const) 141 assert(n.expr.value.__class__ in (str, int, float, unicode)) 142 assert(n.nodes.__class__ == list) 143 assert(len(n.nodes) == 1) 144 assert(n.nodes[0].__class__ == compiler.ast.AssName) 145 assert(n.nodes[0].flags.__class__ == str) 146 assert(n.nodes[0].name.__class__ == str) 147 148 key = n.nodes[0].name.lower() 149 val = str(n.expr.value).strip() 150 151 return (key, val) 152 153 154def _extract_name(n): 155 assert(n.__class__ == compiler.ast.Assign) 156 assert(n.expr.__class__ == compiler.ast.Name) 157 assert(n.nodes.__class__ == list) 158 assert(len(n.nodes) == 1) 159 assert(n.nodes[0].__class__ == compiler.ast.AssName) 160 assert(n.nodes[0].flags.__class__ == str) 161 assert(n.nodes[0].name.__class__ == str) 162 assert(n.expr.name in ('False', 'True', 'None')) 163 164 key = n.nodes[0].name.lower() 165 val = str(n.expr.name) 166 167 return (key, val) 168 169 170def parse_control(path, raise_warnings=False): 171 try: 172 mod = compiler.parseFile(path) 173 except SyntaxError, e: 174 raise ControlVariableException("Error parsing %s because %s" % 175 (path, e)) 176 177 assert(mod.__class__ == compiler.ast.Module) 178 assert(mod.node.__class__ == compiler.ast.Stmt) 179 assert(mod.node.nodes.__class__ == list) 180 181 vars = {} 182 for n in mod.node.nodes: 183 for fn in (_extract_const, _extract_name): 184 try: 185 key, val = fn(n) 186 187 vars[key] = val 188 except AssertionError, e: 189 pass 190 191 return ControlData(vars, path, raise_warnings) 192