一半君的总结纸

听话只听一半君

How can I have Wing send Python or mel code to Maya?

http://mayamel.tiddlyspot.com

Note: Wing can interact with Maya in three different ways. This is one of the three. See an overview here on the whole system: Interaction between Wing and Maya


I using Wing IDE for authoring Python and mel code for Maya, and have come up with a solution (presuming you have the ‘Professional’ version of Wing) to have the code you highlight in Wing execute in Maya (aka ‘evaluate selection’). This lets me completely replace the Script Editor when authoring Python or mel, which we all know doesn’t have the best Python integration… :-S

I’ve added some updated code below that now allows you to publish mel code from Wing to Maya as well.

Note that you can also have Wing recognize .mel files, with some (not full) context sensitive highlighting, correct indentation, scope hilighting, etc: Under Wing ‘Prefs -> Files -> File Types’, ‘insert’ a new file type as mel and set its ‘Mime Type’ to be C++ Source.

There are a few steps involved to get this working. I should point out again this only works with the ‘Professional’ version of Wing, and you’ll need Maya v8.5 or newer: when Maya started supporting Python (below this section I list some old code, for version of Maya8.5 and earlier.)

Important Starting Notes

The biggest hangup with this system is getting Maya to properly open a commandPort, getting a proper socket.socket() connection, and getting Maya to properly connect via maya.connect(). Based on the network settings of your machine, the below code may not work for you as-provided in all instances. Whenever I change machines I seem to have to modify one or more of these areas.

I’ve left code-examples (commented out) for other alternatives that I’ve used on various machines to get these working, so if something fails, you can try using those examples. Otherwise you’ll need to strap on your networking programmer hat and dig into the docs a bit.

Also, when it comes to opening commandPorts, the port number is fairly arbitrary. In the below examples I use 6000, but you can use another number if you wish. Just make sure to update it in both locations: userSetup.mel and the function send_to_maya() in wingHotkeys.py.

#1 – userSetup.mel

In Maya’s userSetup.mel file, add this line to open a network socket. This will later let Wing talk with Maya.

// userSetup.mel
commandPort -name ":6000" -echoOutput;

It appears, if you’re running Maya on Vista \ 64bit, or maybe it’s a Maya2010 thing, you need to call to commandPorttwice to get this working, otherwise your socket will later be refused:

// userSetup.mel
commandPort -name "127.0.0.1:6000" -echoOutput;
commandPort -name ":6000" -echoOutput;

For whatever reason, having your userSetup.pyexecute these commands instead won’t let the below process work. This really confuses me, since Maya claims the port is open. But Wing says the port is refused….

#2 – wingHotkeys.py

The Wing Python module (wingHotkeys.py) and functions inside are authored to do a few things:

  1. Save the text selected in Wing as a temp file on disk.
  2. Ping Maya through the opened command port, and tell Maya to execute the contents of that file. Depending on the type of data sent, either Python or mel, the tool will tell Maya how to intercept it, and execute it.

Again, this code is tailored to Wing IDE’s API, and saved as part of that program’s own “scripts” directory.
Default location (on winXP) of that dir is here:

C:\Documents and Settings\\Application Data\Wing IDE 3\scripts\wingHotkeys.py

On Windows 7:

C:\Users\\AppData\Roaming\Wing IDE 4\scripts\wingHotkeys.py

Functions:

  • send_to_maya() : Function that does the heavy lifting, and calls to executeWingCode.main() (discussed below).
  • python_to_maya() : Wrapper to send the code as Python to Maya. I have this mapped to ctrl+p. (Wing hotkeys don’t allow args, so you need to author wrapper functions)
  • mel_to_maya() : Wrapper to send the code as mel to Maya. I have this mapped to ctrl+m.

If you already have a wingHotkeys.py module for Wing, you can just add the below code to it:

# wingHotkeys.py
# Author:  Eric Pavey - warpcat@sbcglobal.net

import wingapi
import socket
import os

def getWingText():
   """
   Based on the Wing API, get the selected text, and return it
   """
   editor = wingapi.gApplication.GetActiveEditor()
   if editor is None:
      return
   doc = editor.GetDocument()
   start, end = editor.GetSelection()
   txt = doc.GetCharRange(start, end)
   return txt

def send_to_maya(language):
   """
   Send the selected code to be executed in Maya

   language : string : either 'mel' or 'python'
   """
   # The commandPort you opened in userSetup.mel.  Make sure this matches!
   commandPort = 6000

   if language != "mel" and language != "python":
      raise ValueError("Expecting either 'mel' or 'python'")

   # Save the text to a temp file.  If we're dealing with mel, make sure it
   # ends with a semicolon, or Maya could become angered!
   txt = getWingText()
   if language == 'mel':
      if not txt.endswith(';'):
         txt += ';'
   # This saves a temp file on Window.  Mac\Linux will probably need to
   # change this to support their OS.
   tempFile = os.path.join(os.environ['TMP'], 'wingData.txt')
   f = open(tempFile, "w")
   f.write(txt)
   f.close()

   # Create the socket that will connect to Maya,  Opening a socket can vary from
   # machine to machine, so if one way doesn't work, try another... :-S
   #mSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   #mSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) # Works!
   # More generic code for socket creation thanks to Derek Crosby:
   res = socket.getaddrinfo("localhost", commandPort, socket.AF_UNSPEC, socket.SOCK_STREAM)
   af, socktype, proto, canonname, sa = res[0]
   mSocket = socket.socket(af, socktype, proto)

   # Now ping Maya over the command-port
   try:
      # Make our socket-> Maya connection:   There are different connection ways
      # which vary between machines, so sometimes you need to try different
      # solutions to get it to work... :-S
      #mSocket.connect(("127.0.0.1", commandPort))
      #mSocket.connect(("::1",commandPort))  #works!
      mSocket.connect(("localhost", commandPort))

      # Send our code to Maya:
      mSocket.send('python("import executeWingCode; executeWingCode.main(\'%s\')")'%language)
   except Exception, e:
      print "Send to Maya fail:", e

   mSocket.close()

def python_to_maya():
   """Send the selected Python code to Maya"""
   send_to_maya('python')

def mel_to_maya():
   """Send the selected code to Maya as mel"""
   send_to_maya('mel')
#3 – executeWingCode.py

3. The Python module execPythonCode.py is the one Wing’s send_to_maya() function (above, step 2) triggers. It is what physically evaluates the code executed in Wing, in Maya.
Be sure to save this in a location seen by Maya’s Python path.

"""
executeWingCode.py
Eric Pavey - 2011-03-23
Module that Maya calls to when Wing pings it through a socket, telling Maya
to execute the commands in the temp file as either Python or mel code.
"""
import __main__
import os
import maya.OpenMaya as om

def main(codeType):
    """
    Evaluate the temp file on disk, made by Wing, in Maya.

    codeType : string : Supports either 'python' or 'mel'

    """
    tempFile = os.path.join(os.environ['TEMP'], 'wingData.txt').replace("\\", "/")
    if os.access(tempFile , os.F_OK):
        # open and print the file in Maya:
        f =  open(tempFile , "r")
        lines = f.readlines()
        for line in lines:
            print line.rstrip()
        f.close()
        print "\n",

        if codeType == "python":
            # execute the file contents in Maya:
            f = open(tempFile , "r")
            exec(f, __main__.__dict__, __main__.__dict__)
            f.close()

        elif codeType == "mel":
            melCmd = 'source "%s"'%tempFile
            # This causes the "// Result: " line to show up in the Script Editor:
            om.MGlobal.executeCommand(melCmd, True, True)
    else:
        print "No temp file exists: " + tempFile

The key here for the Python execution, is the exec command updating the __main__.__dict__ dictionary with any defined variable names passed in from Wing. It is effectively adding them to the ‘main’, or ‘builtin’ scope of Python. If this doesn’thappen, after the code is executed, you won’t be able to access any variables created\changed from within Maya.

For mel, calling to OpenMaya.MGlobal.executeCommand allows for the result of the execution to be printed to the Script Editor, just like you had originally executed it there.

#4 – Finish

That’s it: You can now highlight code in Wing (either Python or mel), and via a wing hotkey, have it execute directly in Maya. I use it every day…

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: