Changeset 456
- Timestamp:
- 08/25/10 17:28:08 (21 months ago)
- Location:
- branches/parameter_set_schema_validation
- Files:
-
- 4 modified
-
src/parameters/__init__.py (modified) (5 diffs)
-
src/parameters/validators.py (modified) (3 diffs)
-
test/test_parameters.py (modified) (2 diffs)
-
test/test_validators.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/parameter_set_schema_validation/src/parameters/__init__.py
r450 r456 193 193 global_dict.update(update_namespace) 194 194 195 196 D=None 195 197 try: 196 198 D = eval(s, global_dict) 197 except SyntaxError ,e:199 except SyntaxError as e: 198 200 raise SyntaxError("Invalid string for ParameterSet definition: %s\n%s" % (s,e)) 201 199 202 return D or {} 200 203 … … 229 232 pstr = f.read() 230 233 self._url = initialiser 234 235 231 236 except IOError: 232 237 pstr = initialiser … … 235 240 f.close() 236 241 237 initialiser = ParameterSet.read_from_str(pstr,update_namespace) 242 243 # is it a yaml url? 244 if self._url: 245 import urlparse, os.path 246 o = urlparse.urlparse(self._url) 247 base,ext = os.path.splitext(o.path) 248 if ext in ['.yaml','.yml']: 249 import yaml 250 initialiser = yaml.load(pstr) 251 else: 252 initialiser = ParameterSet.read_from_str(pstr,update_namespace) 253 else: 254 initialiser = ParameterSet.read_from_str(pstr,update_namespace) 255 238 256 239 257 # By this stage, `initialiser` should be a dict. Iterate through it, … … 297 315 return dict.__getitem__(self,split[0])[split[1]] 298 316 317 def flat_add(self,name,value): 318 """ Like __setitem__, but it will add ParametSet({}) objects 319 into the namespace tree if needed. """ 320 321 split = name.split('.',1) 322 if len(split)==1: 323 dict.__setitem__(self,name,value) 324 else: 325 # nested set 326 try: 327 ps = dict.__getitem__(self,split[0]) 328 except KeyError: 329 # setting nested name without parent existing 330 # create parent 331 ps = ParameterSet({}) 332 dict.__setitem__(self,split[0],ps) 333 # and try again 334 ps.flat_add(split[1],value) 335 299 336 def __setitem__(self,name,value): 300 337 """ Modified set that detects dots '.' in the names and goes down the … … 306 343 else: 307 344 # nested set 308 try: 309 dict.__getitem__(self,split[0])[split[1]]=value 310 except KeyError: 311 # setting nested name without parent existing 312 # create parent 313 dict.__setitem__(self,split[0],{}) 314 # and try again 315 dict.__getitem__(self,split[0])[split[1]]=value 345 dict.__getitem__(self,split[0])[split[1]]=value 346 316 347 317 348 # should __len__() be the usual dict length, or the flattened length? Probably the former for consistency with dicts -
branches/parameter_set_schema_validation/src/parameters/validators.py
r450 r456 24 24 25 25 def validate(self, leaf): 26 return is subclass(leaf,type)26 return isinstance(leaf, self.type) 27 27 28 28 def __repr__(self): … … 77 77 value = x[1] 78 78 if isinstance(value, SchemaBase): 79 self [key] = value79 self.flat_add(key,value) 80 80 else: 81 self[key] = Subclass(type=type(value)) 82 83 84 85 # Schema ParameterSet types 86 87 88 89 90 class CongruencyValidator: 91 pass 92 93 94 81 self.flat_add(key,Subclass(type=type(value))) 82 83 84 85 86 class ValidationError(Exception): 87 def __init__(self, path='',schema_base=None, parameter=None ): 88 self.path = path 89 self.schema_base = schema_base 90 self.parameter = parameter 91 def __str__(self): 92 return 'validation error @ %s: parameter "%s" failed against schema: %s' % (self.path, self.parameter, self.schema_base) 93 94 95 96 class CongruencyValidator(object): 97 """ 98 A CongruencyValidator validates a ParameterSet against a ParameterSchema 99 either returning True, or raising a ValidationError with the path, SchemaBase subclass 100 and parameter value for which the validation failed. 101 102 The CongruencyValidator expects all names defined in the schema to be present in the parameter set 103 and vice-versa, and will run validation for each item in the namespace tree. 104 105 The validation functionality is available via the "validate" member 106 CongruencyValidator.validate(parameter_set, parameter_schema) 107 108 example: 109 110 validator = CongruencyValidator() 111 112 try: 113 validator.validate(parameter_set,parameter_schema) 114 except ValidationError, e: 115 116 117 """ 118 119 def __init__(self): 120 pass 121 122 123 def validate(self, parameter_set, parameter_schema): 124 """ 125 CongruencyValidator.validate(parameter_set, parameter_schema) 126 127 validates a ParameterSet against a ParameterSchema 128 either returning True, or raising a ValidationError with the path and SchemaBase subclass 129 for which validation failed. 130 131 132 expects all names defined in the schema to be present in the parameter set 133 and vice-versa, and will run validation for each item in the namespace tree. 134 135 See als0: CongruencyValidator docstring. 136 137 """ 138 139 ps = parameter_set 140 schema = parameter_schema 141 142 ps_keys = set() 143 schema_keys = set() 144 145 for path,sb in schema.flat(): 146 try: 147 val = ps[path] 148 except KeyError: 149 e = ValidationError(path=path,schema_base=sb,parameter='<MISSING>') 150 raise e 151 if not sb.validate(val): 152 e = ValidationError(path=path,schema_base=sb,parameter=val) 153 raise e 154 155 156 for path,val in ps.flat(): 157 try: 158 sb = schema[path] 159 except KeyError: 160 e = ValidationError(path=path,schema_base='<MISSING>',parameter=val) 161 raise e 162 163 return True 164 165 95 166 96 167 def congruent_dicts(template, candidate, subset=False,parent_path=''): … … 149 220 NeuroTools.parameters.Subclass = Subclass 150 221 NeuroTools.parameters.CongruencyValidator = CongruencyValidator 151 152 153 222 NeuroTools.parameters.ValidationError = ValidationError 223 224 225 226 227 -
branches/parameter_set_schema_validation/test/test_parameters.py
r355 r456 86 86 ps2 = ParameterSet({'a': 1, 'b':2}) 87 87 self.assertEqual(ps1, ps2) 88 89 def test_create_from_flat_iterator(self): 90 ps = ParameterSet({'a':1, 'b':2}, label="PS1") 91 ps2 = ParameterSet({'ps':ps, 'c':19}, label="PS2") 92 ps3 = ParameterSet({'hello': 'world', 'ps2': ps2, 'null': None, 93 'true': False, 'mylist': [1,2,3,4], 94 'mydict': {'c': 3, 'd':4}, 'yourlist': [1,2,{'e':5, 'f':6}], 95 }, label="PS3") 96 ps4 = ParameterSet({}) 97 for x in ps3.flat(): 98 ps4.flat_add(x[0],x[1]) 99 self.assertEqual(ps4, ps3) 100 88 101 89 102 def test_create_with_syntax_error(self): … … 95 108 def test_create_with_invalid_initialiser(self): 96 109 self.assertRaises(TypeError, ParameterSet, object) 110 111 def test_create_yaml_url(self): 112 import tempfile, yaml 113 114 conf1_str = """ 115 # user info 116 username: joe 117 email: joe@example.com 118 119 # recipes 120 recipes: 121 all: /somewhere1/file1.xml 122 specific: /somewhere2/file2.xml 123 """ 124 125 ps = ParameterSet 126 127 tf = tempfile.NamedTemporaryFile(suffix='.yaml') 128 tf.file.writelines(conf1_str) 129 130 tf.file.flush() 131 tf.file.seek(0) 132 133 ps = ParameterSet("file://"+tf.name) 134 135 tf.close() 136 137 ps1 = ParameterSet(yaml.load(conf1_str)) 138 assert ps1 == ps 139 140 141 142 97 143 98 144 class ParameterSetSaveLoadTest(unittest.TestCase): -
branches/parameter_set_schema_validation/test/test_validators.py
r454 r456 48 48 'true': NeuroTools.parameters.validators.Subclass(type=bool), 49 49 'yourlist': NeuroTools.parameters.validators.Subclass(type=list), 50 'ps2': {'ps.a': NeuroTools.parameters.validators.Subclass(type=int), 51 'c': NeuroTools.parameters.validators.Subclass(type=int), 52 'ps.b': NeuroTools.parameters.validators.Subclass(type=int)}, 'null': NeuroTools.parameters.validators.Subclass(type=NoneType), 'mydict': {'c': NeuroTools.parameters.validators.Subclass(type=int), 'd': NeuroTools.parameters.validators.Subclass(type=int)}, 'hello': NeuroTools.parameters.validators.Subclass(type=str)} 50 'ps2': {'ps': {'a':NeuroTools.parameters.validators.Subclass(type=int), 51 'b':NeuroTools.parameters.validators.Subclass(type=int)}, 52 'c': NeuroTools.parameters.validators.Subclass(type=int)}, 53 'null': NeuroTools.parameters.validators.Subclass(type=type(None)), 54 'mydict': {'c': NeuroTools.parameters.validators.Subclass(type=int), 55 'd': NeuroTools.parameters.validators.Subclass(type=int)}, 56 'hello': NeuroTools.parameters.validators.Subclass(type=str)}) 53 57 54 58 … … 63 67 64 68 69 def test_validate_generated_schema(self): 70 s1 = ParameterSchema(ps3) 71 72 v = CongruencyValidator() 73 assert v.validate(ps3,s1)==True 74 65 75 def test_simple_validate(self): 76 v = CongruencyValidator() 77 assert v.validate(ps3,schema3)==True 78 79 def test_validation_failure_info(self): 80 """ Test the error output for an failed validation against a schema""" 81 66 82 s1 = ParameterSchema(ps3) 67 print s168 #print ps3.flatten()69 83 84 s1.ps2.ps.a = Subclass(type=float) 85 v = CongruencyValidator() 86 r = False 87 try: 88 r = v.validate(ps3,s1) 89 except Exception as e: 90 assert isinstance(e,ValidationError) 91 assert e.path=='ps2.ps.a' 92 assert e.parameter==ps3.ps2.ps.a 93 assert e.schema_base==s1.ps2.ps.a 94 assert r==False 70 95 71 96 def test_congruent_dicts(self):
