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 MayaThe below examples I've gotten to work repeatedly on Windows and Mac.
I use
Wing IDE when 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 (Python
or mel) you
highlight in Wingexecute in Maya (aka 'evaluate selection'). Also known as
REPL. This lets me completely replace the Script Editor when authoring Python
or mel.
Note that you can 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 number of 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
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:
mayaWingServer.py
and the function
send_to_maya()
in
wingHotkeys.py
.
Overview of the below code:
- Maya launches, creates a listener-server waiting for input from Wing.
- In Wing, the user executes a hotkey that sends the highlighted text from Wing to a temp text file. At the same time, over a
commandPort
it pings Maya and tells it to evaluate the text file. - Maya's server receives the ping, processes the text file, and evaluates it in Maya, as if it was executed from the Script Editor
#1 - userSetup.py & mayaWingServer.py
Starting with Maya 2013, the only success I've had getting Wing to talk to Maya is over a 'server' connection, rather than a more simplistic
commandPort
connection.
The module
mayaWingServer.py
should be authored and placed in the same directory as the user
userSetup.py
file. When Maya starts up, it should be called to (via
userSetup.py
) thus launching a listener-server running in a separate thread that will wait for data incoming from Wing, and when it receives it, process the data.
"""
mayaWingServer.py
Author : Eric Pavey - 2012-10-23
"""
import sys
import socket
import threading
import maya.utils as mu
import maya.OpenMaya as om
import executeWingCode
#-----------------
PORT = 6000 # Needs to be the same value as authored in wingHotkeys.py below.
SIZE = 1024
BACKLOG = 5
def processDataInMaya(data):
"""
This function is designed to be passed as the 'processFunc' arg of
the mayaServer function. It is mainly a try\except wrapper around the
executeWingCode.main() function.
data : string : The data passed from wing. Currently this is 'python' or 'mel'.
"""
try:
# If we don't evaluate in maya.util.executeInMainThreadWithResult(),
# Maya can crash, and that's no good.
mu.executeInMainThreadWithResult(executeWingCode.main, data)
except Exception, e:
om.MGlobal.displayError("Encountered exception: %s"%e)
def server(processFunc=processDataInMaya, port=PORT, backlog=BACKLOG, size=SIZE):
"""
Create a server that will listen for incoming data from Wing, and process it.
Modified example taken from:
http://ilab.cs.byu.edu/python/socket/echoserver.html
The server will wait to recieve data from a single client. When it receives
data, it will 'process' it via the processFunc function.
Parameters :
processFunc : function : A function object that will
process the data recieved by the client. It should accept a single
string argument.
port : int : Default to global PORT. The port to connect to.
backlog : int : Default to global BACKLOG. The number of connections the
server can have waiting.
size : int : Default to global SIZE. The size in bytes to recieve back from
the client.
"""
host = ''
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((host,port))
except:
print "Tried to open port %s, but failed: It's probably already open\n"%port
return
s.listen(backlog)
print "Starting Python server, listening on port %s...\n"%port
while True:
client, address = s.accept() # client is a socket object
data = client.recv(size)
if data:
processFunc(data)
client.close()
def startServer():
"""
When Maya starts up, execute this to start the Wing listener server:
"""
threading.Thread(target=server).start()
The
userSetup.py
file should import the above module, and call to
startSever()
:
# userSetup.py
import maya.cmds as mc
# Need to defer the execution, or on Mac it can fail...
mc.evalDeferred("import mayaWingServer; mayaWingServer.startServer()", lowestPriority=True)
If you don't have a
userSetup.py
file, you can make a new one and stick it here (PC):
C:\Users\<USERNAME>\Documents\maya\python\userSetup.py
Or here (Mac):
/Users/<USERNAME>/Library/Preferences/Autodesk/maya/scripts/userSetup.py
Older notes:
Up until Maya 2013, the below code was all that was needed to get a
commandPort
opened and let Wing talk to Maya. But something happened in 2013 that broke all this, thus the above code was generated.
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 commandPort
twice 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.py
execute 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:
- Save the text selected in Wing as a temp file on disk.
- 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\<userName>\Application Data\Wing IDE 3\scripts\wingHotkeys.py
On Windows 7:
C:\Users\<userName>\AppData\Roaming\Wing IDE 4\scripts\wingHotkeys.py
On Mac:
/Users/<userName>/.wingide4/scripts/wingHotkeys.py
Note for Mac: The /.wingide4
directory seems to be hidden in Finder. To access it, open a Terminal, cd to that folder, and execute:
$ open .
To launch a Finder to that folder.
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
.
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.
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
import tempfile
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 port the sever is listening on in mayaWingServer.py :
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 += ';'
# Cross-platform way to get a temp dir:
tempDir = tempfile.gettempdir()
tempFile = os.path.join(tempDir, '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) # works in 2013...
#mSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
# 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)) # works in 2013...
#mSocket.connect(("::1",commandPort))
mSocket.connect(("localhost", commandPort)) # 2016, mac
# Send our code to Maya:
# It is intercepted via the function processDataInMaya(), created via mayaWingServer.py
mSocket.send(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
executeWingCode.py
is the one Wing's
send_to_maya()
function (above, step 2) triggers via the Maya listener-sever. 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 (probably same dir as
userSetup.py
).
"""
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 tempfile
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'
"""
# Cross-platform way to get a temp dir:
tempDir = tempfile.gettempdir()
tempFile = os.path.join(tempDir, 'wingData.txt').replace("\\", "/")
if os.access(tempFile , os.F_OK):
# Print the lines from the file in Maya:
with open(tempFile, "r") as f:
for line in f.readlines():
print line.rstrip()
print "\n",
if codeType == "python":
# execute the file contents in Maya:
with open(tempFile , "r") as f:
exec(f, __main__.__dict__, __main__.__dict__)
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 Wing-generated 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't happen, 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...
Older methods:
- For Maya versions 8 and earlier (Maya 8.5 has Python embedded, yah!)
- Thanks to Hamish McKenzie "macaroniKazoo" on highend3d.com
- First, in Maya, create an INET domain on the local host at the command port:
- Win2000 syntax is "
computerName:portNumber
", I've wondered why you don't have to specify the computerName here?
commandPort -n ":5055";
import socket
maya = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
maya.connect(("127.0.0.1", 5055))
- Then, to actually have Python talk to Maya:
maya.send('print "I am typing in Python, but I see it in Maya!\\n";')
- Of course, you have to embed your mel commands in the Python syntax.
- Python library docs on 'socket' HERE
- What's so special about '127.0.0.1'? Check Wikipedia HERE