Package mrv :: Package maya :: Package automation :: Module qa
[hide private]
[frames] | no frames]

Source Code for Module mrv.maya.automation.qa

  1  # -*- coding: utf-8 -*- 
  2  """Specialization of workflow to allow checks to be natively implemented in MEL """ 
  3  __docformat__ = "restructuredtext" 
  4   
  5  from mrv.automation.qa import QACheck, QACheckAttribute, QACheckResult 
  6  from mrv.maya.util import Mel 
  7  from mrv.dge import _NodeBaseCheckMeta 
  8  import sys 
  9  import logging 
 10  log = logging.getLogger("mrv.maya.automation.qa") 
 11   
 12  __all__ = ("QAMELCheckAttribute", "QAMELCheck", "QAMetaMel", "QAMELMixin") 
13 14 15 -class QAMELCheckAttribute( QACheckAttribute ):
16 """Attribute identifying a MEL check carrying additional mel specific attributes""" 17 pass
18
19 20 -class QAMELCheck( QACheck ):
21 """Specialized version of the QACheck allowing to use our own MEL attribute 22 contianiing more information""" 23 check_attribute_cls = QAMELCheckAttribute
24
25 26 -class QAMetaMel( _NodeBaseCheckMeta ):
27 """Metaclass allowing to create plugs based on a MEL implementation, allowing 28 to decide whether checks are Python or MEL implemented, but still running natively 29 in python""" 30 @classmethod
31 - def _getMelChecks( metacls, index_proc, check_cls ):
32 """ 33 :return: list( checkInstance, ... ) list of checkinstances represeting 34 mel based checkes 35 :param index_proc: method returning the index declaring the tests 36 :param check_cls: class used to instance new checks""" 37 output = list() 38 try: 39 index = Mel.call( index_proc ) 40 except RuntimeError, e: 41 log.warn( str( e ) ) 42 else: 43 # assure its working , never fail here 44 if len( index ) % 3 == 0: 45 iindex = iter( index ) 46 for checkname, description, can_fix in zip( iindex, iindex, iindex ): 47 # check name - it may not contain spaces for now 48 if " " in checkname: 49 log.warn( "Invalid name: %s - it may not contain spaces, use CamelCase or underscores" % checkname ) 50 continue 51 # END name check 52 53 plug = check_cls( annotation = description, has_fix = int( can_fix ) ) 54 plug.setName( checkname ) 55 output.append( plug ) 56 # END for each information tuple 57 # END if index is valid 58 else: 59 log.warn( "Invalid proc index returned by %s" % index_proc ) 60 # END index has valid format 61 # END index could be retrieved 62 63 return output
64
65 - def __new__( metacls, name, bases, clsdict ):
66 """Search for configuration attributes allowing to auto-generate plugs 67 referring to the respective mel implementation""" 68 index_proc = clsdict.get( "mel_index_proc", None ) 69 check_cls = clsdict.get( "check_plug_cls", QAMELCheck ) 70 static_plugs = clsdict.get( "static_mel_plugs", True ) 71 72 if static_plugs and index_proc and check_cls is not None: 73 check_list = metacls._getMelChecks( index_proc, check_cls ) 74 for check in check_list: 75 clsdict[ check.name() ] = check 76 # END create plugs 77 78 # finally create the class 79 newcls = super( QAMetaMel, metacls ).__new__( metacls, name, bases, clsdict ) 80 return newcls
81
82 83 -class QAMELMixin( object ):
84 """Base class allowing to process MEL baesd plugs as created by our metaclass 85 86 :note: this class assumes it is used on a process 87 88 **Configuration**: 89 The following variables MUST be used to setup this class once you have derived 90 from it: 91 92 * mel_index_proc: 93 produdure name with signature func( ) returning string array in following format: 94 [n*3+0] = checkname : the name of the check, use CamelCase names or names_with_underscore 95 The checkname is also used as id to identify the check lateron 96 [n*3+1] = description: Single sentence desciption of the check targeted at the end user 97 [n*3+2] = can_fix: Boolean value indicating whether the check can also fix the issue 98 99 * mel_check_proc: 100 procedure called to actually process the given check, signature is: 101 func( check_name, should_fix ) 102 returning list of strings as follows: 103 104 [0] = x number of fixed items 105 [1] = header 106 [1:1+x] = x fixed items 107 [2+x:n] = n invalid items 108 109 items are either objects or in general anything you check for. The check is 110 considered to be failed if there is at least one invalid item. 111 112 If you fixed items, all previously failed items should now be returned as 113 valid items 114 115 static_mel_plugs: 116 Please note that your class must implemnent plugs and extend the super class 117 result by the result of `listMELChecks` to dynamically retrieve the available 118 checks 119 """ 120 __metaclass__ = QAMetaMel 121 122 #{ Configuration 123 124 # see class docs 125 mel_index_proc = None 126 127 # see class docs 128 mel_check_proc = None 129 130 # if True, the mel based checks will be created as class members upon class 131 # creation. If False, they will be retrieved on demand whenever plugs are 132 # queried. The latter one can be slow, but might be required if the indices 133 # are dynamically generated 134 static_mel_plugs = True 135 136 # qa check result compatible class to be used as container for MEL return values 137 check_result_cls = QACheckResult 138 139 # qa check plug class to use for the plugs to be created - it will always default 140 # to QACheck 141 check_plug_cls = QAMELCheck 142 #} END configuration 143
144 - def listMELChecks( self ):
145 """ 146 :return: list all checks ( Plugs ) available on this class that are implemented 147 in MEL""" 148 return self.listChecks( predicate = lambda p: isinstance( p.attr , QAMELCheckAttribute ) )
149
150 - def isMELCheck( self, check ):
151 """ 152 :return: True if the given check plug is implemented in MEL and can be handled 153 there accordingly""" 154 plug = check 155 try: 156 plug = check.plug 157 except AttributeError: 158 pass 159 160 return isinstance( plug.attr, QAMELCheckAttribute )
161
162 - def _rval_to_checkResult( self, string_array, **kwargs ):
163 """:return: check result as parsed fom string array 164 :param kwargs: will be given to initializer of check result instance""" 165 if not string_array: 166 return self.check_result_cls( **kwargs ) 167 168 assert len( string_array ) > 1 # need a header at least 169 170 num_fixed = int( string_array[0] ) 171 end_num_fixed = 2 + num_fixed 172 173 kwargs[ 'header' ] = string_array[1] 174 kwargs[ 'fixed_items' ] = string_array[ 2 : end_num_fixed ] 175 kwargs[ 'failed_items' ] = string_array[ end_num_fixed : ] 176 177 return self.check_result_cls( **kwargs )
178 179 180 @classmethod
181 - def melChecks( cls, predicate = lambda p: True ):
182 """:return: list of MEL checks ( plugs ) representing checks defined by MEL 183 :param predicate: only return plug if predicate( item ) yield True""" 184 return [ c for c in QAMetaMel._getMelChecks( cls.mel_index_proc, cls.check_plug_cls ) if predicate( c ) ]
185
186 - def handleMELCheck( self, check, mode ):
187 """Called to handle the given check in the given mode 188 189 :raise RuntimeError: If MEL throws an error 190 :return: QACheckResult of the result generated by MEL""" 191 assert self.mel_check_proc 192 assert isinstance( check.attr, QAMELCheckAttribute ) 193 194 rval = Mel.call( self.mel_check_proc, check.name(), int( mode == self.eMode.fix ) ) 195 196 return self._rval_to_checkResult( rval )
197