Example #1
0
def loadApiToMelBridge():

    data = startup.loadCache( 'mayaApiMelBridge', 'the API-MEL bridge', useVersion=False, compressed=True )
    if data is not None:
        # maya 8.5 fix: convert dict to defaultdict
        bridge, overrides = data
        bridge = _util.defaultdict(dict, bridge)
        return bridge, overrides

    # no bridge cache exists. create default
    bridge = _util.defaultdict(dict)

    # no api overrides exist. create default
    overrides = {}

    return bridge, overrides
    def parse(self, apiClassName):

        self.enums = {}
        self.pymelEnums = {}
        self.methods=util.defaultdict(list)
        self.currentMethod=None
        self.badEnums = []

        for proto in self.iterProto(apiClassName):

            methodName, returnType = self.getMethodNameAndOutput(proto)
            if methodName is None: continue
            # convert to unicode
            self.currentMethod = str(methodName)
            if self.currentMethod == 'void(*':
                continue
            # ENUMS
            if returnType == 'enum':
                self.xprint( "ENUM", returnType)
                #print returnType, methodName
                try:
                    #print enumList
                    enumData = self.parseEnums(proto)
                    self.enums[self.currentMethod] = enumData[0]
                    self.pymelEnums[self.currentMethod] = enumData[1]

                except AttributeError, msg:
                    _logger.error("FAILED ENUM: %s", msg)
                    import traceback
                    _logger.debug(traceback.format_exc())

            # ARGUMENTS
            else:
                self.xprint( "RETURN", returnType)

                # Static methods
                static = False
                try:
                    res = proto.findAll('code')
                    if res:
                        code = res[-1].string
                        if code and code.strip() == '[static]':
                            static = True
                except IndexError: pass

                if self.isObsolete(proto):
                    continue

                names, types, typeQualifiers, defaults = self.parseTypes(proto)

                try:
                    directions, docs, methodDoc, returnDoc, deprecated = self.parseMethodArgs(proto, returnType, names, types, typeQualifiers)
                except AssertionError, msg:
                    _logger.error(self.formatMsg("FAILED", str(msg)))
                    continue
                except AttributeError:
                    import traceback
                    _logger.error(self.formatMsg(traceback.format_exc()))
                    continue
Example #3
0
    def __init__(self, apiModule, version=None, verbose=False, enumClass=tuple):
        self.version = versions.installName() if version is None else version
        self.apiModule = apiModule
        self.verbose = verbose
        self.docloc = mayaDocsLocation('2009' if self.version=='2008' else self.version)
        self.enumClass = enumClass
        if not os.path.isdir(self.docloc):
            raise IOError, "Cannot find maya documentation. Expected to find it at %s" % self.docloc

        self.enums = {}
        self.pymelEnums = {}
        self.methods=util.defaultdict(list)
        self.currentMethod=None
        self.badEnums = []
    def __init__(self, apiModule, version=None, verbose=False, enumClass=tuple,
                 docLocation=None):
        self.version = versions.installName() if version is None else version
        self.apiModule = apiModule
        self.verbose = verbose
        if docLocation is None:
            docLocation = mayaDocsLocation('2009' if self.version=='2008' else self.version)
        self.docloc = docLocation
        self.enumClass = enumClass
        if not os.path.isdir(self.docloc):
            raise IOError, "Cannot find maya documentation. Expected to find it at %s" % self.docloc

        self.enums = {}
        self.pymelEnums = {}
        self.methods=util.defaultdict(list)
        self.currentMethod=None
        self.badEnums = []
Example #5
0
    def parse(self, apiClassName):

        self.enums = {}
        self.pymelEnums = {}
        self.methods=util.defaultdict(list)
        self.currentMethod=None
        self.badEnums = []

        self.apiClassName = apiClassName
        self.apiClass = getattr(self.apiModule, self.apiClassName)


        self.docfile = os.path.join( self.docloc , 'API', self.getClassFilename() + '.html' )

        _logger.info( "parsing file %s" , self.docfile )

        f = open( self.docfile )

        soup = BeautifulSoup( f.read(), convertEntities='html' )
        f.close()


        for proto in soup.body.findAll( 'div', **{'class':'memproto'} ):

            returnDoc = ''

            # NAME AND RETURN TYPE
            memb = proto.findAll( 'td', **{'class':'memname'} )[0]
            buf = [ x.strip() for x in memb.findAll( text=True )]
            if len(buf) ==1:
                buf = [ x for x in buf[0].split() if x not in ['const', 'unsigned'] ]
                if len(buf)==1:
                    returnType = None
                    methodName = buf[0]
                else:
                    returnType = ''.join(buf[:-1])
                    methodName = buf[-1]
            else:
                returnType = buf[0]
                methodName = buf[1]
                buf = [ x for x in buf[0].split() if x not in ['const', 'unsigned'] ]
                if len(buf) > 1:
                    returnType += buf[0]
                    methodName = buf[1]

            methodName = methodName.split('::')[-1]

            # convert operators to python special methods
            if methodName.startswith('operator'):
                methodName = self.getOperatorName(methodName)

                if methodName is None: continue

            # no MStatus in python
            if returnType in ['MStatus', 'void']:
                returnType = None
            else:
                returnType = self.handleEnums(returnType)

            # convert to unicode
            self.currentMethod = str(methodName)

            #constructors and destructors
            if self.currentMethod.startswith('~') or self.currentMethod == self.apiClassName:
                continue

            # ENUMS
            if returnType == 'enum':
                self.xprint( "ENUM", returnType)
                #print returnType, methodName
                try:
                    enumValues={}
                    enumDocs={}
                    for em in proto.findNextSiblings( 'div', limit=1)[0].findAll( 'em'):
                        enumKey = str(em.contents[-1])
                        try:
                            enumVal = getattr(self.apiClass, enumKey)
                        except:
                            _logger.warn( "%s.%s of enum %s does not exist" % ( self.apiClassName, enumKey, self.currentMethod))
                            enumVal = None
                        enumValues[ enumKey ] = enumVal

                        docItem = em.next.next.next.next.next

                        if isinstance( docItem, NavigableString ):
                            enumDocs[enumKey] = str(docItem).strip()
                        else:
                            enumDocs[enumKey] = str(docItem.contents[0]).strip()

                    pymelEnumList = self.getPymelEnums( enumValues )
                    for val, pyval in zip(enumValues,pymelEnumList):
                        enumDocs[pyval] = enumDocs[val]

                    enumInfo = {'values' : util.Enum(self.currentMethod, enumValues, multiKeys=True),
                                'valueDocs' : enumDocs,

                                  #'doc' : methodDoc
                                }

                    #print enumList

                    self.enums[self.currentMethod] = enumInfo
                    self.pymelEnums[self.currentMethod] = util.Enum(self.currentMethod, pymelEnumList, multiKeys=True)

                except AttributeError, msg:
                    _logger.error( "FAILED ENUM: %s", msg )

            # ARGUMENTS
            else:
                self.xprint( "RETURN", returnType)

                argInfo={}
                argList=[]
                defaults={}
                names=[]
                directions={}
                docs={}
                inArgs=[]
                outArgs=[]
                types ={}
                typeQualifiers={}
                methodDoc = ''
                deprecated = False

                # Static methods
                static = False
                try:
                    code = proto.findAll('code')[-1].string
                    if code and code.strip() == '[static]':
                        static = True
                except IndexError: pass

                tmpTypes=[]
                # TYPES
                for paramtype in proto.findAll( 'td', **{'class':'paramtype'} ) :
                    buf = []
                    [ buf.extend(x.split()) for x in paramtype.findAll( text=True ) ] #if x.strip() not in ['', '*', '&', 'const', 'unsigned'] ]
                    buf = [ str(x.strip()) for x in buf if x.strip() ]

                    i=0
                    for i, each in enumerate(buf):
                        if each not in [ '*', '&', 'const', 'unsigned']:
                            argtype = buf.pop(i)
                            break
                    else:
                        # We didn't find any arg type - therefore everything
                        # in buf is in the set('*', '&', 'const', 'unsigned')
                        # ... so it's implicitly an unsigned int
                        argtype = 'int'

                    if 'unsigned' in buf and argtype in ('char','int', 'int2',
                                                         'int3', 'int4'):
                        argtype = 'u' + argtype

                    argtype = self.handleEnums(argtype)

                    #print '\targtype', argtype, buf
                    tmpTypes.append( (argtype, buf) )

                # ARGUMENT NAMES
                i = 0
                for paramname in  proto.findAll( 'td', **{'class':'paramname'} )  :
                    buf = [ x.strip() for x in paramname.findAll( text=True ) if x.strip() not in['',','] ]
                    if buf:
                        argname = buf[0]
                        data = buf[1:]

                        type, qualifiers = tmpTypes[i]
                        default=None
                        joined = ''.join(data).strip()

                        if joined:
                            # break apart into index and defaults :  '[3] = NULL'
                            brackets, default = re.search( '([^=]*)(?:\s*=\s*(.*))?', joined ).groups()

                            if brackets:
                                numbuf = re.split( r'\[|\]', brackets)
                                if len(numbuf) > 1:
                                    # Note that these two args need to be cast differently:
                                    #   int2 foo;
                                    #   int bar[2];
                                    # ... so, instead of storing the type of both as
                                    # 'int2', we make the second one 'int__array2'
                                    type = type + '__array' + numbuf[1]
                                else:
                                    print "this is not a bracketed number", repr(brackets), joined

                            if default is not None:
                                try:
                                    # Constants
                                    default = {
                                        'true' : True,
                                        'false': False,
                                        'NULL' : None
                                    }[default]
                                except KeyError:
                                    try:
                                        if type in ['int', 'uint','long', 'uchar']:
                                            default = int(default)
                                        elif type in ['float', 'double']:
                                            # '1.0 / 24.0'
                                            if '/' in default:
                                                default = eval(default.encode('ascii', 'ignore'))
                                            # '1.0e-5F'  --> '1.0e-5'
                                            elif default.endswith('F'):
                                                default = float(default[:-1])
                                            else:
                                                default = float(default)
                                        else:
                                            default = self.handleEnumDefaults(default, type)
                                    except ValueError:
                                        default = self.handleEnumDefaults(default, type)
                                # default must be set here, because 'NULL' may be set to back to None, but this is in fact the value we want
                                self.xprint('DEFAULT', default)
                                defaults[argname] = default

                        types[argname] = type
                        typeQualifiers[argname] = qualifiers
                        names.append(argname)
                        i+=1

                try:
                    # ARGUMENT DIRECTION AND DOCUMENTATION
                    addendum = proto.findNextSiblings( 'div', limit=1)[0]
                    #try: self.xprint( addendum.findAll(text=True ) )
                    #except: pass

                    #if addendum.findAll( text = re.compile( '(This method is obsolete.)|(Deprecated:)') ):

                    if addendum.findAll( text=lambda x: x in self.OBSOLETE_MSG ):
                        self.xprint( "OBSOLETE" )
                        self.currentMethod = None
                        continue

                    #if self.currentMethod == 'createColorSet': raise NotImplementedError
                    if addendum.findAll( text=lambda x: x in self.DEPRECATED_MSG ):
                        self.xprint( "DEPRECATED" )
                        #print self.apiClassName + '.' + self.currentMethod + ':' + ' DEPRECATED'
                        deprecated = True


                    methodDoc = ' '.join( addendum.p.findAll( text=True ) )

                    tmpDirs = []
                    tmpNames = []
                    tmpDocs = []

                    #extraInfo = addendum.dl.table
                    extraInfos = addendum.findAll('table')

                    if extraInfos:
                        #print "NUMBER OF TABLES", len(extraInfos)
                        for extraInfo in extraInfos:
                            tmpDirs += extraInfo.findAll( text=lambda text: text in ['[in]', '[out]'] )

                            #tmpNames += [ em.findAll( text=True, limit=1 )[0] for em in extraInfo.findAll( 'em') ]
                            tmpNames = []
                            for tr in extraInfo.findAll( 'tr'):
                                assert tr, "could not find name tr"
                                em = tr.findNext( 'em' )
                                assert tr, "could not find name em"
                                name = em.findAll( text=True, limit=1 )[0]
                                tmpNames.append(name)

#                            for td in extraInfo.findAll( 'td' ):
#                                assert td, "could not find doc td"
#                                for doc in td.findAll( text=lambda text: text.strip(), recursive=False) :
#                                    if doc: tmpDocs.append( ''.join(doc) )

                            for doc in [td.findAll( text=lambda text: text.strip(), recursive=False) for td in extraInfo.findAll( 'td' )]:
                                if doc: tmpDocs.append( ''.join(doc) )


                        assert len(tmpDirs) == len(tmpNames) == len(tmpDocs), 'names and types lists are of unequal lengths: %s vs. %s vs. %s' % (tmpDirs, tmpNames, tmpDocs)
                        assert sorted(tmpNames) == sorted(typeQualifiers.keys()), 'name list mismatch %s %s' %  (sorted(tmpNames), sorted(typeQualifiers.keys()) )

                        #self.xprint(  sorted(tmpNames), sorted(typeQualifiers.keys()), sorted(typeQualifiers.keys()) )

                        for name, dir, doc in zip(tmpNames, tmpDirs, tmpDocs) :
                            if dir == '[in]':
                                # attempt to correct bad in/out docs
                                if re.search(r'\b([fF]ill|[sS]tor(age)|(ing))|([rR]esult)', doc ):
                                    _logger.warn( "%s.%s(%s): Correcting suspected output argument '%s' based on doc '%s'" % (
                                                                        self.apiClassName,self.currentMethod,', '.join(names), name, doc))
                                    dir = 'out'
                                elif not re.match( 'set[A-Z]', self.currentMethod) and '&' in typeQualifiers[name] and types[name] in ['int', 'double', 'float', 'uint', 'uchar']:
                                    _logger.warn( "%s.%s(%s): Correcting suspected output argument '%s' based on reference type '%s &' ('%s')'" % (
                                                                        self.apiClassName,self.currentMethod,', '.join(names), name, types[name], doc))
                                    dir = 'out'
                                else:
                                    dir = 'in'
                            elif dir == '[out]':
                                if types[name] == 'MAnimCurveChange':
                                    _logger.warn( "%s.%s(%s): Setting MAnimCurveChange argument '%s' to an input arg (instead of output)" % (
                                                                        self.apiClassName,self.currentMethod,', '.join(names), name))
                                    dir = 'in'
                                else:
                                    dir = 'out'
                            else: raise

                            assert name in names
                            directions[name] = dir
                            docs[name] = doc


                        # Documentation for Return Values
                        if returnType:
                            try:
                                returnDocBuf = addendum.findAll( 'dl', limit=1, **{'class':'return'} )[0].findAll( text=True )
                            except IndexError:
                                pass
                            else:
                                if returnDocBuf:
                                    returnDoc = ''.join( returnDocBuf[1:] ).strip('\n')
                                self.xprint(  'RETURN_DOC', repr(returnDoc)  )


                except (AttributeError, AssertionError), msg:
                    self.xprint( "FAILED", str(msg) )
                    pass


#                print names
#                print types
#                print defaults
#                print directions
#                print docs

                for argname in names[:] :
                    type = types[argname]
                    direction = directions.get(argname, 'in')
                    doc = docs.get( argname, '')

                    if type == 'MStatus':
                        types.pop(argname)
                        defaults.pop(argname,None)
                        directions.pop(argname,None)
                        docs.pop(argname,None)
                        idx = names.index(argname)
                        names.pop(idx)
                    else:
                        if direction == 'in':
                            inArgs.append(argname)
                        else:
                            outArgs.append(argname)
                        argInfo[ argname ] = {'type': type, 'doc': doc }

                # correct bad outputs
                if self.isGetMethod() and not returnType and not outArgs:
                    for argname in names:
                        if '&' in typeQualifiers[argname]:
                            doc = docs.get(argname, '')
                            directions[argname] = 'out'
                            idx = inArgs.index(argname)
                            inArgs.pop(idx)
                            outArgs.append(argname)

                            _logger.warn( "%s.%s(%s): Correcting suspected output argument '%s' because there are no outputs and the method is prefixed with 'get' ('%s')" % (
                                                                           self.apiClassName,self.currentMethod, ', '.join(names), argname, doc))

                # now that the directions are correct, make the argList
                for argname in names:
                    type = types[argname]
                    direction = directions.get(argname, 'in')
                    data = ( argname, type, direction)
                    if self.verbose: self.xprint( "ARG", data )
                    argList.append(  data )

                methodInfo = { 'argInfo': argInfo,
                              'returnInfo' : { 'type' : returnType, 'doc' : returnDoc },
                              'args' : argList,
                              'returnType' : returnType,
                              'inArgs' : inArgs,
                              'outArgs' : outArgs,
                              'doc' : methodDoc,
                              'defaults' : defaults,
                              #'directions' : directions,
                              'types' : types,
                              'static' : static,
                              'typeQualifiers' : typeQualifiers,
                              'deprecated' : deprecated }
                self.methods[self.currentMethod].append(methodInfo)

                # reset
                self.currentMethod=None
Example #6
0
def _defaultdictdict(cls, val=None):
    if val is None:
        return _util.defaultdict(dict)
    else:
        return _util.defaultdict(dict, val)
Example #7
0
def _defaultdictdict(cls, val=None):
    if val is None:
        return _util.defaultdict(dict)
    else:
        return _util.defaultdict(dict, val)
Example #8
0
    def parse(self, apiClassName):

        self.enums = {}
        self.pymelEnums = {}
        self.methods = util.defaultdict(list)
        self.currentMethod = None
        self.badEnums = []

        self.apiClassName = apiClassName
        self.apiClass = getattr(self.apiModule, self.apiClassName)

        self.docfile = os.path.join(self.docloc, 'API',
                                    self.getClassFilename() + '.html')

        _logger.info("parsing file %s", self.docfile)

        f = open(self.docfile)

        soup = BeautifulSoup(f.read(), convertEntities='html')
        f.close()

        for proto in soup.body.findAll('div', **{'class': 'memproto'}):

            returnDoc = ''

            # NAME AND RETURN TYPE
            memb = proto.findAll('td', **{'class': 'memname'})[0]
            buf = [x.strip() for x in memb.findAll(text=True)]
            if len(buf) == 1:
                buf = [
                    x for x in buf[0].split()
                    if x not in ['const', 'unsigned']
                ]
                if len(buf) == 1:
                    returnType = None
                    methodName = buf[0]
                else:
                    returnType = ''.join(buf[:-1])
                    methodName = buf[-1]
            else:
                returnType = buf[0]
                methodName = buf[1]
                buf = [
                    x for x in buf[0].split()
                    if x not in ['const', 'unsigned']
                ]
                if len(buf) > 1:
                    returnType += buf[0]
                    methodName = buf[1]

            methodName = methodName.split('::')[-1]

            # convert operators to python special methods
            if methodName.startswith('operator'):
                methodName = self.getOperatorName(methodName)

                if methodName is None: continue

            # no MStatus in python
            if returnType in ['MStatus', 'void']:
                returnType = None
            else:
                returnType = self.handleEnums(returnType)

            # convert to unicode
            self.currentMethod = str(methodName)

            #constructors and destructors
            if self.currentMethod.startswith(
                    '~') or self.currentMethod == self.apiClassName:
                continue

            # ENUMS
            if returnType == 'enum':
                self.xprint("ENUM", returnType)
                #print returnType, methodName
                try:
                    enumValues = {}
                    enumDocs = {}
                    for em in proto.findNextSiblings('div',
                                                     limit=1)[0].findAll('em'):
                        enumKey = str(em.contents[-1])
                        try:
                            enumVal = getattr(self.apiClass, enumKey)
                        except:
                            _logger.warn("%s.%s of enum %s does not exist" %
                                         (self.apiClassName, enumKey,
                                          self.currentMethod))
                            enumVal = None
                        enumValues[enumKey] = enumVal

                        docItem = em.next.next.next.next.next

                        if isinstance(docItem, NavigableString):
                            enumDocs[enumKey] = str(docItem).strip()
                        else:
                            enumDocs[enumKey] = str(
                                docItem.contents[0]).strip()

                    pymelEnumList = self.getPymelEnums(enumValues)
                    for val, pyval in zip(enumValues, pymelEnumList):
                        enumDocs[pyval] = enumDocs[val]

                    enumInfo = {
                        'values':
                        util.Enum(self.currentMethod,
                                  enumValues,
                                  multiKeys=True),
                        'valueDocs':
                        enumDocs,

                        #'doc' : methodDoc
                    }

                    #print enumList

                    self.enums[self.currentMethod] = enumInfo
                    self.pymelEnums[self.currentMethod] = util.Enum(
                        self.currentMethod, pymelEnumList, multiKeys=True)

                except AttributeError, msg:
                    _logger.error("FAILED ENUM: %s", msg)

            # ARGUMENTS
            else:
                self.xprint("RETURN", returnType)

                argInfo = {}
                argList = []
                defaults = {}
                names = []
                directions = {}
                docs = {}
                inArgs = []
                outArgs = []
                types = {}
                typeQualifiers = {}
                methodDoc = ''
                deprecated = False

                # Static methods
                static = False
                try:
                    code = proto.findAll('code')[-1].string
                    if code and code.strip() == '[static]':
                        static = True
                except IndexError:
                    pass

                tmpTypes = []
                # TYPES
                for paramtype in proto.findAll('td', **{'class': 'paramtype'}):
                    buf = []
                    [
                        buf.extend(x.split())
                        for x in paramtype.findAll(text=True)
                    ]  #if x.strip() not in ['', '*', '&', 'const', 'unsigned'] ]
                    buf = [str(x.strip()) for x in buf if x.strip()]

                    i = 0
                    for i, each in enumerate(buf):
                        if each not in ['*', '&', 'const', 'unsigned']:
                            argtype = buf.pop(i)
                            break
                    else:
                        # We didn't find any arg type - therefore everything
                        # in buf is in the set('*', '&', 'const', 'unsigned')
                        # ... so it's implicitly an unsigned int
                        argtype = 'int'

                    if 'unsigned' in buf and argtype in ('char', 'int', 'int2',
                                                         'int3', 'int4'):
                        argtype = 'u' + argtype

                    argtype = self.handleEnums(argtype)

                    #print '\targtype', argtype, buf
                    tmpTypes.append((argtype, buf))

                # ARGUMENT NAMES
                i = 0
                for paramname in proto.findAll('td', **{'class': 'paramname'}):
                    buf = [
                        x.strip() for x in paramname.findAll(text=True)
                        if x.strip() not in ['', ',']
                    ]
                    if buf:
                        argname = buf[0]
                        data = buf[1:]

                        type, qualifiers = tmpTypes[i]
                        default = None
                        joined = ''.join(data).strip()

                        if joined:
                            joined = joined.encode('ascii', 'ignore')
                            # break apart into index and defaults :  '[3] = NULL'
                            brackets, default = re.search(
                                '([^=]*)(?:\s*=\s*(.*))?', joined).groups()

                            if brackets:
                                numbuf = re.split(r'\[|\]', brackets)
                                if len(numbuf) > 1:
                                    # Note that these two args need to be cast differently:
                                    #   int2 foo;
                                    #   int bar[2];
                                    # ... so, instead of storing the type of both as
                                    # 'int2', we make the second one 'int__array2'
                                    type = type + '__array' + numbuf[1]
                                else:
                                    print "this is not a bracketed number", repr(
                                        brackets), joined

                            if default is not None:
                                try:
                                    # Constants
                                    default = {
                                        'true': True,
                                        'false': False,
                                        'NULL': None
                                    }[default]
                                except KeyError:
                                    try:
                                        if type in [
                                                'int', 'uint', 'long', 'uchar'
                                        ]:
                                            default = int(default)
                                        elif type in ['float', 'double']:
                                            # '1.0 / 24.0'
                                            if '/' in default:
                                                default = eval(default)
                                            # '1.0e-5F'  --> '1.0e-5'
                                            elif default.endswith('F'):
                                                default = float(default[:-1])
                                            else:
                                                default = float(default)
                                        else:
                                            default = self.handleEnumDefaults(
                                                default, type)
                                    except ValueError:
                                        default = self.handleEnumDefaults(
                                            default, type)
                                # default must be set here, because 'NULL' may be set to back to None, but this is in fact the value we want
                                self.xprint('DEFAULT', default)
                                defaults[argname] = default

                        types[argname] = type
                        typeQualifiers[argname] = qualifiers
                        names.append(argname)
                        i += 1

                try:
                    # ARGUMENT DIRECTION AND DOCUMENTATION
                    addendum = proto.findNextSiblings('div', limit=1)[0]
                    #try: self.xprint( addendum.findAll(text=True ) )
                    #except: pass

                    #if addendum.findAll( text = re.compile( '(This method is obsolete.)|(Deprecated:)') ):

                    if addendum.findAll(text=lambda x: x in self.OBSOLETE_MSG):
                        self.xprint("OBSOLETE")
                        self.currentMethod = None
                        continue

                    #if self.currentMethod == 'createColorSet': raise NotImplementedError
                    if addendum.findAll(
                            text=lambda x: x in self.DEPRECATED_MSG):
                        self.xprint("DEPRECATED")
                        #print self.apiClassName + '.' + self.currentMethod + ':' + ' DEPRECATED'
                        deprecated = True

                    methodDoc = ' '.join(addendum.p.findAll(text=True))

                    tmpDirs = []
                    tmpNames = []
                    tmpDocs = []

                    #extraInfo = addendum.dl.table
                    extraInfos = addendum.findAll('table')

                    if extraInfos:
                        #print "NUMBER OF TABLES", len(extraInfos)
                        for extraInfo in extraInfos:
                            tmpDirs += extraInfo.findAll(
                                text=lambda text: text in ['[in]', '[out]'])

                            #tmpNames += [ em.findAll( text=True, limit=1 )[0] for em in extraInfo.findAll( 'em') ]
                            tmpNames = []
                            for tr in extraInfo.findAll('tr'):
                                assert tr, "could not find name tr"
                                em = tr.findNext('em')
                                assert tr, "could not find name em"
                                name = em.findAll(text=True, limit=1)[0]
                                tmpNames.append(name)

#                            for td in extraInfo.findAll( 'td' ):
#                                assert td, "could not find doc td"
#                                for doc in td.findAll( text=lambda text: text.strip(), recursive=False) :
#                                    if doc: tmpDocs.append( ''.join(doc) )

                            for doc in [
                                    td.findAll(text=lambda text: text.strip(),
                                               recursive=False)
                                    for td in extraInfo.findAll('td')
                            ]:
                                if doc: tmpDocs.append(''.join(doc))

                        assert len(tmpDirs) == len(tmpNames) == len(
                            tmpDocs
                        ), 'names and types lists are of unequal lengths: %s vs. %s vs. %s' % (
                            tmpDirs, tmpNames, tmpDocs)
                        assert sorted(tmpNames) == sorted(typeQualifiers.keys(
                        )), 'name list mismatch %s %s' % (
                            sorted(tmpNames), sorted(typeQualifiers.keys()))

                        #self.xprint(  sorted(tmpNames), sorted(typeQualifiers.keys()), sorted(typeQualifiers.keys()) )

                        for name, dir, doc in zip(tmpNames, tmpDirs, tmpDocs):
                            if dir == '[in]':
                                # attempt to correct bad in/out docs
                                if re.search(
                                        r'\b([fF]ill|[sS]tor(age)|(ing))|([rR]esult)',
                                        doc):
                                    _logger.warn(
                                        "%s.%s(%s): Correcting suspected output argument '%s' based on doc '%s'"
                                        %
                                        (self.apiClassName, self.currentMethod,
                                         ', '.join(names), name, doc))
                                    dir = 'out'
                                elif not re.match(
                                        'set[A-Z]', self.currentMethod
                                ) and '&' in typeQualifiers[name] and types[
                                        name] in [
                                            'int', 'double', 'float', 'uint',
                                            'uchar'
                                        ]:
                                    _logger.warn(
                                        "%s.%s(%s): Correcting suspected output argument '%s' based on reference type '%s &' ('%s')'"
                                        %
                                        (self.apiClassName, self.currentMethod,
                                         ', '.join(names), name, types[name],
                                         doc))
                                    dir = 'out'
                                else:
                                    dir = 'in'
                            elif dir == '[out]':
                                if types[name] == 'MAnimCurveChange':
                                    _logger.warn(
                                        "%s.%s(%s): Setting MAnimCurveChange argument '%s' to an input arg (instead of output)"
                                        %
                                        (self.apiClassName, self.currentMethod,
                                         ', '.join(names), name))
                                    dir = 'in'
                                else:
                                    dir = 'out'
                            else:
                                raise

                            assert name in names
                            directions[name] = dir
                            docs[name] = doc

                        # Documentation for Return Values
                        if returnType:
                            try:
                                returnDocBuf = addendum.findAll(
                                    'dl', limit=1,
                                    **{'class':
                                       'return'})[0].findAll(text=True)
                            except IndexError:
                                pass
                            else:
                                if returnDocBuf:
                                    returnDoc = ''.join(
                                        returnDocBuf[1:]).strip('\n')
                                self.xprint('RETURN_DOC', repr(returnDoc))

                except (AttributeError, AssertionError), msg:
                    self.xprint("FAILED", str(msg))
                    pass

#                print names
#                print types
#                print defaults
#                print directions
#                print docs

                for argname in names[:]:
                    type = types[argname]
                    direction = directions.get(argname, 'in')
                    doc = docs.get(argname, '')

                    if type == 'MStatus':
                        types.pop(argname)
                        defaults.pop(argname, None)
                        directions.pop(argname, None)
                        docs.pop(argname, None)
                        idx = names.index(argname)
                        names.pop(idx)
                    else:
                        if direction == 'in':
                            inArgs.append(argname)
                        else:
                            outArgs.append(argname)
                        argInfo[argname] = {'type': type, 'doc': doc}

                # correct bad outputs
                if self.isGetMethod() and not returnType and not outArgs:
                    for argname in names:
                        if '&' in typeQualifiers[argname]:
                            doc = docs.get(argname, '')
                            directions[argname] = 'out'
                            idx = inArgs.index(argname)
                            inArgs.pop(idx)
                            outArgs.append(argname)

                            _logger.warn(
                                "%s.%s(%s): Correcting suspected output argument '%s' because there are no outputs and the method is prefixed with 'get' ('%s')"
                                % (self.apiClassName, self.currentMethod,
                                   ', '.join(names), argname, doc))

                # now that the directions are correct, make the argList
                for argname in names:
                    type = types[argname]
                    direction = directions.get(argname, 'in')
                    data = (argname, type, direction)
                    if self.verbose: self.xprint("ARG", data)
                    argList.append(data)

                methodInfo = {
                    'argInfo': argInfo,
                    'returnInfo': {
                        'type': returnType,
                        'doc': returnDoc
                    },
                    'args': argList,
                    'returnType': returnType,
                    'inArgs': inArgs,
                    'outArgs': outArgs,
                    'doc': methodDoc,
                    'defaults': defaults,
                    #'directions' : directions,
                    'types': types,
                    'static': static,
                    'typeQualifiers': typeQualifiers,
                    'deprecated': deprecated
                }
                self.methods[self.currentMethod].append(methodInfo)

                # reset
                self.currentMethod = None