__init__.py (17928B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\evegraphics\validation\__init__.py 2 from __future__ import print_function 3 import os 4 import time 5 import sys 6 from evegraphics.validation.commonUtilities import BaseValidationRule 7 from evegraphics.validation.errors import SingleObjectValidationError, ValidationError, MultipleValidationErrors 8 import blue 9 import trinity 10 11 def GetObjectAttribute(obj, attribute): 12 if attribute is not None: 13 if hasattr(obj, attribute): 14 return getattr(obj, attribute) 15 else: 16 print("object '%s' has no attribute '%s'" % (obj, attribute)) 17 return 18 return obj 19 20 21 def _FormatPath(stack): 22 return '/'.join(((getattr(x, 'name') if getattr(x, 'name', '') else type(x).__name__) for x in stack)) 23 24 25 _jessicaSkipValidationObjects = {} 26 27 def ValidationAttributeFilter(obj, attr): 28 try: 29 return _jessicaSkipValidationObjects[type(obj), attr] 30 except KeyError: 31 try: 32 use = ':jessica-skip-validation:' not in obj.TypeInfo()[2][attr]['description'] 33 except Exception: 34 use = True 35 36 _jessicaSkipValidationObjects[type(obj), attr] = use 37 return use 38 39 40 class ObjectLink(object): 41 42 def GetSourceObject(self): 43 return None 44 45 def GetBinding(self): 46 return None 47 48 def GetBoundObject(self): 49 raise NotImplementedError() 50 51 def GetBoundAttribute(self): 52 raise NotImplementedError() 53 54 def SetBoundAttribute(self, attr): 55 raise NotImplementedError() 56 57 def Patch(self, old, new): 58 raise NotImplementedError() 59 60 def IsDestination(self): 61 raise NotImplementedError() 62 63 def IsSource(self): 64 raise NotImplementedError() 65 66 67 class ControllerActionLink(ObjectLink): 68 69 def __init__(self, action, parentController): 70 self._action = action 71 self._parentController = parentController 72 73 def GetBoundObject(self): 74 boundObject = self._action.GetDestination() 75 if not boundObject and self._action.delayBinding: 76 boundObject = trinity.ResolveObjectPath(self._action.path, {'Owner': self._parentController.GetOwner()}) 77 return boundObject 78 79 def GetBoundAttribute(self): 80 return self._action.attribute 81 82 def SetBoundAttribute(self, attr): 83 self._action.attribute = attr 84 85 def IsDestination(self): 86 return True 87 88 def IsSource(self): 89 return False 90 91 def Patch(self, old, new): 92 if self.GetBoundObject() == old: 93 if self._action.path: 94 raise NotImplementedError() 95 else: 96 self._action.destination = new 97 return True 98 return False 99 100 101 class SourceBindingLink(ObjectLink): 102 103 def __init__(self, binding): 104 self._binding = binding 105 106 def GetBinding(self): 107 return self._binding 108 109 def GetBoundObject(self): 110 return self._binding.sourceObject 111 112 def GetBoundAttribute(self): 113 return self._binding.sourceAttribute 114 115 def SetBoundAttribute(self, attr): 116 self._binding.sourceAttribute = attr 117 118 def Patch(self, old, new): 119 if self.GetBoundObject() == old: 120 self._binding.sourceObject = new 121 return True 122 return False 123 124 def IsDestination(self): 125 return False 126 127 def IsSource(self): 128 return True 129 130 131 class SourceDynamicBindingLink(ObjectLink): 132 133 def __init__(self, binding): 134 self._binding = binding 135 136 def GetBinding(self): 137 return self._binding 138 139 def GetBoundObject(self): 140 return self._binding.source 141 142 def GetBoundAttribute(self): 143 return self._binding.sourceObjectAttribute 144 145 def SetBoundAttribute(self, attr): 146 self._binding.sourceObjectAttribute = attr 147 148 def Patch(self, old, new): 149 if self.GetBoundObject() == old: 150 self._binding.source = new 151 return True 152 return False 153 154 def IsDestination(self): 155 return False 156 157 def IsSource(self): 158 return True 159 160 161 class DestinationBindingLink(ObjectLink): 162 163 def __init__(self, binding): 164 self._binding = binding 165 166 def GetBinding(self): 167 return self._binding 168 169 def GetSourceObject(self): 170 return self._binding.sourceObject 171 172 def GetBoundObject(self): 173 return self._binding.destinationObject 174 175 def GetBoundAttribute(self): 176 return self._binding.destinationAttribute 177 178 def SetBoundAttribute(self, attr): 179 self._binding.destinationAttribute = attr 180 181 def Patch(self, old, new): 182 if self.GetBoundObject() == old: 183 self._binding.destinationObject = new 184 return True 185 return False 186 187 def IsDestination(self): 188 return True 189 190 def IsSource(self): 191 return False 192 193 194 class SmartLightMeshBindingLink(ObjectLink): 195 196 def __init__(self, meshRenderer, area): 197 self._meshRenderer = meshRenderer 198 self._area = area 199 200 def GetBinding(self): 201 return self._meshRenderer 202 203 def GetBoundObject(self): 204 if self._area is not None: 205 if self._area.effect is not None: 206 parameters = self._area.effect.parameters 207 param = parameters.FindByName(self.GetBoundAttribute()) 208 return param 209 210 def GetBoundAttribute(self): 211 if self._meshRenderer: 212 return self._meshRenderer.shaderParamColorName 213 return '' 214 215 def IsDestination(self): 216 return True 217 218 def IsSource(self): 219 return False 220 221 222 class ExternalParameterLink(ObjectLink): 223 224 def __init__(self, binding): 225 self._binding = binding 226 227 def GetBinding(self): 228 return self._binding 229 230 def GetBoundObject(self): 231 return self._binding.destinationObject 232 233 def GetBoundAttribute(self): 234 return self._binding.destinationAttribute 235 236 def IsDestination(self): 237 return True 238 239 def IsSource(self): 240 return True 241 242 243 class ValidationContext(object): 244 245 def __init__(self, rootObject, rules): 246 self.errors = [] 247 self.root = rootObject 248 self._rules = rules 249 self._arguments = {} 250 self._stack = [] 251 self._skipObjects = [] 252 self._stackStrs = ['root'] 253 self._destinationBindings = None 254 self._sourceBindings = None 255 self._allBindings = None 256 self._currentRule = None 257 self.cache = {} 258 self._attributeFilter = ValidationAttributeFilter 259 260 def GetStack(self): 261 return self._stack 262 263 def GetStackAsStr(self): 264 return '.'.join(self._stackStrs) 265 266 def GetTop(self): 267 return self._stack[-1] 268 269 def GetArgument(self, argumentType): 270 return self._arguments[argumentType] 271 272 def Walk(self, obj, callback, seen): 273 try: 274 hash(obj) 275 key = obj 276 except TypeError: 277 key = id(obj) 278 279 if key in seen: 280 return 281 seen.add(key) 282 self._stack.append(obj) 283 try: 284 callback() 285 if isinstance(obj, list) or getattr(obj, '__bluetype__', '') == 'blue.List': 286 for i, each in enumerate(obj): 287 if each in self._skipObjects: 288 continue 289 self._stackStrs.append(str(i)) 290 self.Walk(each, callback, seen) 291 self._stackStrs.pop() 292 293 else: 294 for each in dir(obj): 295 member = getattr(obj, each) 296 if each.startswith('_') or callable(member): 297 continue 298 if isinstance(member, (int, 299 float, 300 long, 301 str, 302 unicode)): 303 continue 304 if member in self._skipObjects: 305 continue 306 if isinstance(member, tuple) and all((isinstance(x, (int, 307 float, 308 long, 309 str, 310 unicode)) for x in member)): 311 continue 312 if self._attributeFilter and not self._attributeFilter(obj, each): 313 continue 314 self._stackStrs.append(each) 315 self.Walk(member, callback, seen) 316 self._stackStrs.pop() 317 318 finally: 319 self._stack.pop() 320 321 def GetArguments(self): 322 args = set() 323 rulesWithArguments = [ x for x in map(lambda r: (r, r.GetArguments()), self._rules) if x[1] ] 324 ruleMap = {} 325 326 def inner(): 327 t = type(self._stack[-1]) 328 if t not in ruleMap: 329 ruleMap[t] = [ x for x in rulesWithArguments if x[0].CanApplyToTypeOf(self._stack[-1]) ] 330 for each in ruleMap[t]: 331 if each[0].Applies(self): 332 args.update(each[1]) 333 334 self.Walk(self.root, inner, set()) 335 return args 336 337 def Validate(self, arguments): 338 self.errors = [] 339 self.cache = {} 340 self._arguments = arguments 341 self._destinationBindings = None 342 self._sourceBindings = None 343 self._allBindings = None 344 self._currentRule = None 345 self._ruleMap = {} 346 347 def inner(): 348 validated = False 349 t = type(self._stack[-1]) 350 if t not in self._ruleMap: 351 self._ruleMap[t] = [ x for x in self._rules if x.CanApplyToTypeOf(self._stack[-1]) ] 352 for each in self._ruleMap[t]: 353 self._currentRule = each 354 try: 355 validated = each.Apply(self) or validated 356 except BaseException: 357 import traceback 358 self.Error(each, 'Exception in the rule:\n\n' + traceback.format_exc()) 359 360 time.sleep(0) 361 362 self.Walk(self.root, inner, set()) 363 self._currentRule = None 364 365 def SkipObject(self, obj): 366 self._skipObjects.append(obj) 367 368 def AddError(self, error): 369 if error.rule is None: 370 error.rule = self._currentRule 371 self.errors.append(error) 372 373 def Error(self, obj, message, actions = ()): 374 self.AddError(SingleObjectValidationError(obj, message, actions)) 375 376 def Expect(self, obj, attribute, rule, message = None, actions = ()): 377 try: 378 objectToValidate = GetObjectAttribute(obj, attribute) 379 if objectToValidate is None: 380 return 381 rule(objectToValidate, message) 382 except AssertionError as e: 383 self.AddError(SingleObjectValidationError(obj, '%s %s' % (attribute, str(e)), actions)) 384 except MultipleValidationErrors as e: 385 for error in e.errors: 386 self.AddError(error) 387 388 def ExpectValue(self, obj, value, rule, message = None, actions = ()): 389 try: 390 rule(value, message) 391 except AssertionError as e: 392 self.AddError(SingleObjectValidationError(obj, '%s %s' % (value, str(e)), actions)) 393 except MultipleValidationErrors as e: 394 for error in e.errors: 395 self.AddError(error) 396 397 def ExpectAny(self, obj, attribute, rule, message): 398 objectToValidate = GetObjectAttribute(obj, attribute) 399 if objectToValidate is None: 400 return 401 for each in objectToValidate: 402 try: 403 rule(each, message) 404 return 405 except AssertionError: 406 pass 407 except MultipleValidationErrors: 408 pass 409 410 self.AddError(SingleObjectValidationError(obj, '%s %s' % (attribute, message))) 411 412 def GetAllObjectBindings(self): 413 bindings = blue.FindInterface(self.root, 'TriValueBinding') 414 allBindings = [ SourceBindingLink(x) for x in bindings ] 415 allBindings.extend((DestinationBindingLink(x) for x in bindings)) 416 allBindings.extend((SourceDynamicBindingLink(x) for x in blue.FindInterface(self.root, 'Tr2DynamicBinding'))) 417 allBindings.extend((ExternalParameterLink(x) for x in blue.FindInterface(self.root, 'Tr2ExternalParameter'))) 418 for slm in blue.FindInterface(self.root, 'EveSmartLightMesh'): 419 if slm.mesh is not None: 420 for area in slm.mesh.GetAllAreas(): 421 allBindings.append(SmartLightMeshBindingLink(slm, area)) 422 423 controllerActions = {} 424 for controller in blue.FindInterface(self.root, 'Tr2Controller'): 425 controllerActions[controller] = [] 426 for stateMachine in controller.stateMachines: 427 for state in stateMachine.states: 428 controllerActions[controller].extend(state.actions) 429 430 actions = blue.FindInterface(self.root, 'Tr2ActionSetValue') 431 actions.extend(blue.FindInterface(self.root, 'Tr2ActionAnimateValue')) 432 for a in actions: 433 for key, val in controllerActions.iteritems(): 434 if a in val: 435 allBindings.append(ControllerActionLink(a, key)) 436 break 437 438 return allBindings 439 440 def RemoveBinding(self, binding): 441 toRemove = None 442 if binding and self._allBindings: 443 for each in self._allBindings: 444 if binding == each.GetBinding(): 445 toRemove = each 446 break 447 448 if toRemove: 449 if self._destinationBindings: 450 cleanupKey = None 451 cleanupName = None 452 for key, each in self._destinationBindings.iteritems(): 453 for name, val in each.iteritems(): 454 if toRemove in val: 455 val.remove(toRemove) 456 cleanupKey = key 457 cleanupName = name 458 break 459 460 if cleanupKey and cleanupName: 461 if len(self._destinationBindings[cleanupKey][cleanupName]) == 0: 462 self._destinationBindings[cleanupKey].pop(cleanupName) 463 if len(self._destinationBindings[cleanupKey]) == 0: 464 self._destinationBindings.pop(cleanupKey) 465 if self._sourceBindings: 466 cleanupKey = None 467 cleanupName = None 468 for key, each in self._sourceBindings.iteritems(): 469 for name, val in each.iteritems(): 470 if toRemove in val: 471 val.remove(toRemove) 472 cleanupKey = key 473 cleanupName = name 474 break 475 476 if cleanupKey and cleanupName: 477 if len(self._sourceBindings[cleanupKey][cleanupName]) == 0: 478 self._sourceBindings[cleanupKey].pop(cleanupName) 479 if len(self._sourceBindings[cleanupKey]) == 0: 480 self._sourceBindings.pop(cleanupKey) 481 self._allBindings.remove(toRemove) 482 483 def GetBindings(self): 484 if self._allBindings is None: 485 self._allBindings = self.GetAllObjectBindings() 486 return self._allBindings 487 488 def GetDestinationBindings(self): 489 if self._destinationBindings is None: 490 allBindings = self.GetBindings() 491 self._destinationBindings = {} 492 for binding in allBindings: 493 if binding.IsDestination(): 494 self._destinationBindings.setdefault(binding.GetBoundObject(), {}).setdefault(binding.GetBoundAttribute(), []).append(binding) 495 496 return self._destinationBindings 497 498 def GetSourceBindings(self): 499 if self._sourceBindings is None: 500 allBindings = self.GetBindings() 501 self._sourceBindings = {} 502 for binding in allBindings: 503 if binding.IsSource(): 504 self._sourceBindings.setdefault(binding.GetBoundObject(), {}).setdefault(binding.GetBoundAttribute(), []).append(binding) 505 506 return self._sourceBindings 507 508 def IsBoundAsDestination(self, obj, attribute = None): 509 if obj.name == 'FresnelFactors': 510 pass 511 return self._IsBound(obj, attribute, self.GetDestinationBindings()) 512 513 def IsBoundAsSource(self, obj, attribute = None): 514 return self._IsBound(obj, attribute, self.GetSourceBindings()) 515 516 def _IsBound(self, obj, attribute, bindings): 517 if attribute is None: 518 return obj in bindings 519 else: 520 boundAttributes = bindings.get(obj, {}) 521 attributeIsBound = attribute in boundAttributes 522 if not attributeIsBound: 523 for boundAttribute in boundAttributes: 524 if boundAttribute.startswith(attribute + '.'): 525 return True 526 527 return attributeIsBound 528 529 530 def FindRules(path = None): 531 if path is None: 532 path = os.path.join(os.path.dirname(__file__), 'validators') 533 rules = [] 534 for root, dirs, files in os.walk(path): 535 if root.lower().endswith('test'): 536 continue 537 for each in files: 538 rules.extend(FindRulesInFile(os.path.join(root, each))) 539 540 return rules 541 542 543 def FindRulesInFile(filePath): 544 rules = [] 545 root = os.path.dirname(filePath) 546 file = os.path.basename(filePath) 547 if file.lower().endswith('.py'): 548 sys.path.insert(0, root) 549 try: 550 module = __import__(os.path.splitext(file)[0]) 551 for name in dir(module): 552 member = getattr(module, name) 553 if isinstance(member, BaseValidationRule): 554 if member.name is None: 555 member.name = '%s.%s' % (os.path.splitext(file)[0], name) 556 rules.append(member) 557 558 finally: 559 del sys.path[0] 560 561 return rules 562 563 564 def InitializeArgumentsFromFilePath(argumentClasses, path, root): 565 return {k:k.CreateFromPath(path, root) for k in argumentClasses}