Esempio n. 1
0
def _pluginLoaded(*args):
    global _pluginData

    if len(args) > 1:
        # 2009 API callback, the args are ( [ pathToPlugin, pluginName ], clientData )
        pluginName = args[0][1]
    else:
        pluginName = args[0]

    if not pluginName:
        return

    # Check to see if plugin is really loaded
    if not (cmds.pluginInfo(pluginName, query=1, loaded=1)):
        return

    # Make sure there are no registered callbacks for this plug-in. It has been
    # reported that some 3rd party plug-ins will enter here twice, causing a
    # "callback id leak" which potentially leads to a crash. The reported
    # scenario was:
    # - Launching mayapy.exe
    # - Opening a Maya scene having a requires statement (to the plug-in)
    # - The plug-in imports pymel, causing initialization and entering here.
    if (pluginName in _pluginData) and 'callbackId' in _pluginData[
            pluginName] and _pluginData[pluginName]['callbackId'] != None:
        _api.MEventMessage.removeCallback(
            _pluginData[pluginName]['callbackId'])

    _logger.debug("Plugin loaded: %s", pluginName)
    _pluginData[pluginName] = {}

    # Commands
    commands = _plugins.pluginCommands(pluginName)

    if commands:
        # clear out the command list first
        _pluginData[pluginName]['commands'] = []
        for funcName in commands:
            try:
                _addPluginCommand(pluginName, funcName)
            except Exception as e:
                _logger.error("Error adding command %s from plugin %s - %s" %
                              (funcName, pluginName, e))
                _logger.debug(traceback.format_exc())

    # Nodes
    try:
        mayaTypes = cmds.pluginInfo(pluginName, query=1, dependNode=1)
    except Exception:
        _logger.error("Failed to get depend nodes list from %s", pluginName)
        mayaTypes = None
    #apiEnums = cmds.pluginInfo(pluginName, query=1, dependNodeId=1)
    if mayaTypes:

        def addPluginPyNodes(*args):
            try:
                id = _pluginData[pluginName].get('callbackId')
            except KeyError:
                _logger.warning("could not find callback id!")
            else:
                if id is not None:
                    _api.MEventMessage.removeCallback(id)
                    if hasattr(id, 'disown'):
                        id.disown()

            _pluginData[pluginName]['dependNodes'] = []
            allTypes = set(cmds.ls(nodeTypes=1))
            for mayaType in mayaTypes:
                # make sure it's a 'valid' type - some plugins list node types
                # that don't show up in ls(nodeTypes=1), and aren't creatable
                # ...perhaps they're abstract types?
                # Unfortunately, can't check this, as only plugin I know of
                # that has such a node - mayalive, mlConstraint - is only
                # available up to 2009, which has a bug with allNodeTypes...
                # Oddly enough, mlConstraint WILL show up in allTypes here,
                # but not after the plugin is loaded / callback finishes...?
                if mayaType not in allTypes:
                    continue
                _addPluginNode(pluginName, mayaType)

        # Note - in my testing, a single _api.MFileIO.isReadingFile() call would
        # also catch opening + referencing operations... but in commit
        # 6e53d7818e9363d55d417c3a80ea7df94c4998ec, a check only against
        # isReadingFile is commented out... so I'm playing it safe, and assuming
        # there are edge cases where isOpeningFile is True but isReadingFile is
        # not

        # Detect if we are currently opening/importing a file and load as a callback versus execute now
        if (_api.MFileIO.isReadingFile() or _api.MFileIO.isOpeningFile()
                or (_versions.current() >= _versions.v2012
                    and _api.MFileIO.isReferencingFile())):
            if _versions.current(
            ) >= _versions.v2012 and _api.MFileIO.isReferencingFile():
                _logger.debug(
                    "Installing temporary plugin-loaded nodes callback - PostSceneRead"
                )
                id = _api.MEventMessage.addEventCallback(
                    'PostSceneRead', addPluginPyNodes)
            elif _api.MFileIO.isImportingFile():
                _logger.debug(
                    "Installing temporary plugin-loaded nodes callback - SceneImported"
                )
                id = _api.MEventMessage.addEventCallback(
                    'SceneImported', addPluginPyNodes)
            else:
                # pre-2012 referencing operations will fall into this branch,
                # which will not work (ie, pre-2012, plugins loaded due to
                # reference loads will not trigger adding of that plugin's
                # PyNodes).
                # While this is obviously less than ideal, no 2011 versions were
                # available for testing when I made the fix for 2012+, and we
                # decided that making nothing worse would be better than
                # potentially introducing problems/instabilities (ie, see
                # messages in commits 6e53d7818e9363d55d417c3a80ea7df94c4998ec
                # and 81bc5ee28f1775a680449fec8724e21e703a52b8).
                _logger.debug(
                    "Installing temporary plugin-loaded nodes callback - SceneOpened"
                )
                id = _api.MEventMessage.addEventCallback(
                    'SceneOpened', addPluginPyNodes)
            _pluginData[pluginName]['callbackId'] = id
            # scriptJob not respected in batch mode, had to use _api
            #cmds.scriptJob( event=('SceneOpened',doSomethingElse), runOnce=1 )
        else:
            _logger.debug("Running plugin-loaded nodes callback")
            # add the callback id as None, so addPluginPyNodes SHOULD know that
            # SOMETHING is always in _pluginData[pluginName]['callbackId'], and
            # if there isn't, then something is wrong...
            _pluginData[pluginName]['callbackId'] = None
            addPluginPyNodes()
Esempio n. 2
0
def _pluginLoaded(*args):
    global _pluginData

    if len(args) > 1:
        # 2009 API callback, the args are ( [ pathToPlugin, pluginName ], clientData )
        pluginName = args[0][1]
    else:
        pluginName = args[0]

    if not pluginName:
        return

    _logger.debug("Plugin loaded: %s", pluginName)
    _pluginData[pluginName] = {}

    # Commands
    commands = _plugins.pluginCommands(pluginName)

    if commands:
        # clear out the command list first
        _pluginData[pluginName]['commands'] = []
        for funcName in commands:
            _addPluginCommand(pluginName, funcName)

    # Nodes
    try:
        mayaTypes = cmds.pluginInfo(pluginName, query=1, dependNode=1)
    except Exception:
        _logger.error("Failed to get depend nodes list from %s", pluginName)
        mayaTypes = None
    #apiEnums = cmds.pluginInfo(pluginName, query=1, dependNodeId=1)
    if mayaTypes:

        def addPluginPyNodes(*args):
            try:
                id = _pluginData[pluginName]['callbackId']
                if id is not None:
                    _api.MEventMessage.removeCallback(id)
                    if hasattr(id, 'disown'):
                        id.disown()
            except KeyError:
                _logger.warning("could not find callback id!")

            _pluginData[pluginName]['dependNodes'] = []
            allTypes = set(cmds.ls(nodeTypes=1))
            for mayaType in mayaTypes:
                # make sure it's a 'valid' type - some plugins list node types
                # that don't show up in ls(nodeTypes=1), and aren't creatable
                # ...perhaps they're abstract types?
                # Unfortunately, can't check this, as only plugin I know of
                # that has such a node - mayalive, mlConstraint - is only
                # available up to 2009, which has a bug with allNodeTypes...
                # Oddly enough, mlConstraint WILL show up in allTypes here,
                # but not after the plugin is loaded / callback finishes...?
                if mayaType not in allTypes:
                    continue
                _addPluginNode(pluginName, mayaType)
                _logger.debug("Adding node: %s" % mayaType)

        # Detect if we are currently opening/importing a file and load as a callback versus execute now
        if _api.MFileIO.isReadingFile() or _api.MFileIO.isOpeningFile():  #or \
            ##           #Referencing still doesn't work because while I can detect when I am referencing in 2012 I don't have
            ##           # an acceptable event to latch on to. Contacting Autodesk to see if we can get one.
            ##            ( _versions.current() >= _versions.v2012 and _api.MFileIO.isReferencingFile()):
            ##            if _api.MFileIO.isReferencingFile():
            ##                _logger.debug("pymel: Installing temporary plugin-loaded nodes callback - postsceneread")
            ##                id = _api.MEventMessage.addEventCallback( 'PostSceneRead', addPluginPyNodes )
            if _api.MFileIO.isImportingFile():
                _logger.debug(
                    "Installing temporary plugin-loaded nodes callback - sceneimported"
                )
                id = _api.MEventMessage.addEventCallback(
                    'SceneImported', addPluginPyNodes)
            else:
                _logger.debug(
                    "Installing temporary plugin-loaded nodes callback - sceneopened"
                )
                id = _api.MEventMessage.addEventCallback(
                    'SceneOpened', addPluginPyNodes)
            _pluginData[pluginName]['callbackId'] = id
            # scriptJob not respected in batch mode, had to use _api
            #cmds.scriptJob( event=('SceneOpened',doSomethingElse), runOnce=1 )
        else:
            _logger.debug("Running plugin-loaded nodes callback")
            # add the callback id as None so that if we fail to get an id in addPluginPyNodes we know something is wrong
            _pluginData[pluginName]['callbackId'] = None
            addPluginPyNodes()
def _pluginLoaded( *args ):
    global _pluginData
    
    if len(args) > 1:
        # 2009 API callback, the args are ( [ pathToPlugin, pluginName ], clientData )
        pluginName = args[0][1]
    else:
        pluginName = args[0]

    if not pluginName:
        return

    _logger.debug("Plugin loaded: %s", pluginName)
    _pluginData[pluginName] = {}

    # Commands
    commands = _plugins.pluginCommands(pluginName)
    
    if commands:
        # clear out the command list first
        _pluginData[pluginName]['commands'] = []
        for funcName in commands:
            _addPluginCommand(pluginName, funcName) 

    # Nodes
    try:
        mayaTypes = cmds.pluginInfo(pluginName, query=1, dependNode=1)
    except Exception:
        _logger.error("Failed to get depend nodes list from %s", pluginName)
        mayaTypes = None
    #apiEnums = cmds.pluginInfo(pluginName, query=1, dependNodeId=1)
    if mayaTypes :
        def addPluginPyNodes(*args):
            try:
                id = _pluginData[pluginName]['callbackId']
                if id is not None:
                    _api.MEventMessage.removeCallback( id )
                    if hasattr(id, 'disown'):
                        id.disown()
            except KeyError:
                _logger.warning("could not find callback id!")

            _pluginData[pluginName]['dependNodes'] = []
            allTypes = set(cmds.ls(nodeTypes=1))
            for mayaType in mayaTypes:
                # make sure it's a 'valid' type - some plugins list node types
                # that don't show up in ls(nodeTypes=1), and aren't creatable
                # ...perhaps they're abstract types?
                # Unfortunately, can't check this, as only plugin I know of
                # that has such a node - mayalive, mlConstraint - is only
                # available up to 2009, which has a bug with allNodeTypes...
                # Oddly enough, mlConstraint WILL show up in allTypes here,
                # but not after the plugin is loaded / callback finishes...?
                if mayaType not in allTypes:
                    continue
                _addPluginNode(pluginName, mayaType)
                _logger.debug("Adding node: %s" % mayaType)

        # Detect if we are currently opening/importing a file and load as a callback versus execute now
        if _api.MFileIO.isReadingFile() or  _api.MFileIO.isOpeningFile(): #or \
##           #Referencing still doesn't work because while I can detect when I am referencing in 2012 I don't have
##           # an acceptable event to latch on to. Contacting Autodesk to see if we can get one.
##            ( _versions.current() >= _versions.v2012 and _api.MFileIO.isReferencingFile()):
##            if _api.MFileIO.isReferencingFile():
##                _logger.debug("pymel: Installing temporary plugin-loaded nodes callback - postsceneread")
##                id = _api.MEventMessage.addEventCallback( 'PostSceneRead', addPluginPyNodes )
            if _api.MFileIO.isImportingFile():
                _logger.debug("Installing temporary plugin-loaded nodes callback - sceneimported")
                id = _api.MEventMessage.addEventCallback( 'SceneImported', addPluginPyNodes )
            else:
                _logger.debug("Installing temporary plugin-loaded nodes callback - sceneopened")
                id = _api.MEventMessage.addEventCallback( 'SceneOpened', addPluginPyNodes )
            _pluginData[pluginName]['callbackId'] = id
            # scriptJob not respected in batch mode, had to use _api
            #cmds.scriptJob( event=('SceneOpened',doSomethingElse), runOnce=1 )
        else:
            _logger.debug("Running plugin-loaded nodes callback")
            # add the callback id as None so that if we fail to get an id in addPluginPyNodes we know something is wrong
            _pluginData[pluginName]['callbackId'] = None
            addPluginPyNodes()
Esempio n. 4
0
def _pluginLoaded( *args ):
    global _pluginData
    
    if len(args) > 1:
        # 2009 API callback, the args are ( [ pathToPlugin, pluginName ], clientData )
        pluginName = args[0][1]
    else:
        pluginName = args[0]

    if not pluginName:
        return

    _logger.debug("Plugin loaded: %s", pluginName)
    _pluginData[pluginName] = {}

    # Commands
    commands = _plugins.pluginCommands(pluginName)
    
    if commands:
        # clear out the command list first
        _pluginData[pluginName]['commands'] = []
        for funcName in commands:
            _addPluginCommand(pluginName, funcName) 

    # Nodes
    try:
        mayaTypes = cmds.pluginInfo(pluginName, query=1, dependNode=1)
    except Exception:
        _logger.error("Failed to get depend nodes list from %s", pluginName)
        mayaTypes = None
    #apiEnums = cmds.pluginInfo(pluginName, query=1, dependNodeId=1)
    if mayaTypes :
        def addPluginPyNodes(*args):
            try:
                id = _pluginData[pluginName].get('callbackId')
            except KeyError:
                _logger.warning("could not find callback id!")
            else:
                if id is not None:
                    _api.MEventMessage.removeCallback( id )
                    if hasattr(id, 'disown'):
                        id.disown()

            _pluginData[pluginName]['dependNodes'] = []
            allTypes = set(cmds.ls(nodeTypes=1))
            for mayaType in mayaTypes:
                # make sure it's a 'valid' type - some plugins list node types
                # that don't show up in ls(nodeTypes=1), and aren't creatable
                # ...perhaps they're abstract types?
                # Unfortunately, can't check this, as only plugin I know of
                # that has such a node - mayalive, mlConstraint - is only
                # available up to 2009, which has a bug with allNodeTypes...
                # Oddly enough, mlConstraint WILL show up in allTypes here,
                # but not after the plugin is loaded / callback finishes...?
                if mayaType not in allTypes:
                    continue
                _addPluginNode(pluginName, mayaType)

        # Note - in my testing, a single _api.MFileIO.isReadingFile() call would
        # also catch opening + referencing operations... but in commit
        # 6e53d7818e9363d55d417c3a80ea7df94c4998ec, a check only against
        # isReadingFile is commented out... so I'm playing it safe, and assuming
        # there are edge cases where isOpeningFile is True but isReadingFile is
        # not
        
        # Detect if we are currently opening/importing a file and load as a callback versus execute now
        if (_api.MFileIO.isReadingFile() or  _api.MFileIO.isOpeningFile() or
                ( _versions.current() >= _versions.v2012
                  and _api.MFileIO.isReferencingFile())):
            if _versions.current() >= _versions.v2012 and _api.MFileIO.isReferencingFile():
                _logger.debug("Installing temporary plugin-loaded nodes callback - PostSceneRead")
                id = _api.MEventMessage.addEventCallback( 'PostSceneRead', addPluginPyNodes )
            elif _api.MFileIO.isImportingFile():
                _logger.debug("Installing temporary plugin-loaded nodes callback - SceneImported")
                id = _api.MEventMessage.addEventCallback( 'SceneImported', addPluginPyNodes )
            else:
                # pre-2012 referencing operations will fall into this branch,
                # which will not work (ie, pre-2012, plugins loaded due to
                # reference loads will not trigger adding of that plugin's
                # PyNodes).
                # While this is obviously less than ideal, no 2011 versions were
                # available for testing when I made the fix for 2012+, and we
                # decided that making nothing worse would be better than
                # potentially introducing problems/instabilities (ie, see
                # messages in commits 6e53d7818e9363d55d417c3a80ea7df94c4998ec
                # and 81bc5ee28f1775a680449fec8724e21e703a52b8).
                _logger.debug("Installing temporary plugin-loaded nodes callback - SceneOpened")
                id = _api.MEventMessage.addEventCallback( 'SceneOpened', addPluginPyNodes )
            _pluginData[pluginName]['callbackId'] = id
            # scriptJob not respected in batch mode, had to use _api
            #cmds.scriptJob( event=('SceneOpened',doSomethingElse), runOnce=1 )
        else:
            _logger.debug("Running plugin-loaded nodes callback")
            # add the callback id as None, so addPluginPyNodes SHOULD know that
            # SOMETHING is always in _pluginData[pluginName]['callbackId'], and
            # if there isn't, then something is wrong...
            _pluginData[pluginName]['callbackId'] = None
            addPluginPyNodes()
    def rebuild(self) :
        """Build and save to disk the list of Maya Python commands and their arguments

        WARNING: will unload existing plugins, then (re)load all maya-installed
        plugins, without making an attempt to return the loaded plugins to the
        state they were at before this command is run.  Also, the act of
        loading all the plugins may crash maya, especially if done from a
        non-GUI session
        """
        # Put in a debug, because this can be crashy
        _logger.debug("Starting CmdCache.rebuild...")

        # With extension can't get docs on unix 64
        # path is
        # /usr/autodesk/maya2008-x64/docs/Maya2008/en_US/Nodes/index_hierarchy.html
        # and not
        # /usr/autodesk/maya2008-x64/docs/Maya2008-x64/en_US/Nodes/index_hierarchy.html

        long_version = versions.installName()

        from parsers import mayaDocsLocation
        cmddocs = os.path.join(mayaDocsLocation(long_version), 'CommandsPython')
        assert os.path.exists(cmddocs), "Command documentation does not exist: %s" % cmddocs

        _logger.info("Rebuilding the maya node hierarchy...")

        # Load all plugins to get the nodeHierarchy / nodeFunctions
        import pymel.api.plugins as plugins

        # We don't want to add in plugin nodes / commands - let that be done
        # by the plugin callbacks.  However, unloading mechanism is not 100%
        # ... sometimes functions get left in maya.cmds... and then trying
        # to use those left-behind functions can cause crashes (ie,
        # FBXExportQuaternion). So check which methods SHOULD be unloaded
        # first, so we know to skip those if we come across them even after
        # unloading the plugin
        pluginCommands = set()
        loadedPlugins = cmds.pluginInfo(q=True, listPlugins=True)
        if loadedPlugins:
            for plug in loadedPlugins:
                plugCmds = plugins.pluginCommands(plug)
                if plugCmds:
                    pluginCommands.update(plugCmds)

        plugins.unloadAllPlugins()

        self.nodeHierarchy = _getNodeHierarchy(long_version)
        nodeFunctions = [ x[0] for x in self.nodeHierarchy ]
        nodeFunctions += nodeTypeToNodeCommand.values()


        _logger.info("Rebuilding the list of Maya commands...")

        #nodeHierarchyTree = trees.IndexedTree(self.nodeHierarchy)
        self.uiClassList = UI_COMMANDS
        self.nodeCommandList = []
        tmpModuleCmds = {}
        for moduleName, longname in moduleNameShortToLong.items():
            tmpModuleCmds[moduleName] = getModuleCommandList( longname, long_version )

        tmpCmdlist = inspect.getmembers(cmds, callable)

        #self.moduleCmds = defaultdict(list)
        self.moduleCmds = dict( (k,[]) for k in moduleNameShortToLong.keys() )
        self.moduleCmds.update( {'other':[], 'runtime': [], 'context': [], 'uiClass': [] } )

        def addCommand(funcName):
            _logger.debug('adding command: %s' % funcName)
            module = getModule(funcName, tmpModuleCmds)

            cmdInfo = {}

            if module:
                self.moduleCmds[module].append(funcName)

            if module != 'runtime':
                cmdInfo = getCmdInfo(funcName, long_version)

                if module != 'windows':
                    if funcName in nodeFunctions:
                        self.nodeCommandList.append(funcName)
                        cmdInfo = testNodeCmd( funcName, cmdInfo, nodeCmd=True, verbose=True  )
                    #elif module != 'context':
                    #    cmdInfo = testNodeCmd( funcName, cmdInfo, nodeCmd=False, verbose=True  )

            cmdInfo['type'] = module
            flags = getCallbackFlags(cmdInfo)
            if flags:
                cmdInfo['callbackFlags'] = flags

            self.cmdlist[funcName] = cmdInfo

#            # func, args, (usePyNode, baseClsName, nodeName)
#            # args = dictionary of command flags and their data
#            # usePyNode = determines whether the class returns its 'nodeName' or uses PyNode to dynamically return
#            # baseClsName = for commands which should generate a class, this is the name of the superclass to inherit
#            # nodeName = most creation commands return a node of the same name, this option is provided for the exceptions
#            try:
#                self.cmdlist[funcName] = args, pymelCmdsList[funcName] )
#            except KeyError:
#                # context commands generate a class based on unicode (which is triggered by passing 'None' to baseClsName)
#                if funcName.startswith('ctx') or funcName.endswith('Ctx') or funcName.endswith('Context'):
#                     self.cmdlist[funcName] = (funcName, args, (False, None, None) )
#                else:
#                    self.cmdlist[funcName] = (funcName, args, () )

        for funcName, _ in tmpCmdlist :
            if funcName in pluginCommands:
                _logger.debug("command %s was a plugin command that should have been unloaded - skipping" % funcName)
                continue
            addCommand(funcName)

        # split the cached data for lazy loading
        cmdDocList = {}
        examples = {}
        for cmdName, cmdInfo in self.cmdlist.iteritems():
            try:
                examples[cmdName] = cmdInfo.pop('example')
            except KeyError:
                pass

            newCmdInfo = {}
            if 'description' in cmdInfo:
                newCmdInfo['description'] = cmdInfo.pop('description')
            newFlagInfo = {}
            if 'flags' in cmdInfo:
                for flag, flagInfo in cmdInfo['flags'].iteritems():
                    newFlagInfo[flag] = { 'docstring' : flagInfo.pop('docstring') }
                newCmdInfo['flags'] = newFlagInfo

            if newCmdInfo:
                cmdDocList[cmdName] = newCmdInfo

        CmdDocsCache().write(cmdDocList)
        CmdExamplesCache().write(examples)