pymxs os.path commands

pymxs os.path commands

malcomarmstrong
Advocate Advocate
3,743 Views
6 Replies
Message 1 of 7

pymxs os.path commands

malcomarmstrong
Advocate
Advocate

Can you tell me why the following does not work when I execute it from a saved file, in the script editor in max, yet running it from the same file in Sublime produces the result I expect?

 

s1 = sys.argv[0]
fileDir = os.path.dirname(__file__)
fileNm = os.path.basename(__file__)
abPth =os.path.dirname(os.path.abspath(__file__))
os_cwd = os.getcwd()
print s1
print fileDir
print fileNm
print abPth
print os_cwd

Max errors with this:

 

Traceback (most recent call last):
NameError: name '__file__' is not defined

I looked (as best as I could) through what I hoped would be the auto complete list for os commands regarding the same commands in the script I executed in sublime with success, but the results were not as expected or gave no result either way on execution.

 

I am assuming that its a formatting issue that I am not implementing correctly as if I try and construct a command with the os functionality provided by pymxs, I am not getting back what I need.

 

pyms_os_autocomplete.jpg

 

I also tried the following, getting pretty much the same results from Max and Sublime, except for line 2:

 

print os.path.__file__
print os.path.basename(os.path.abspath(os.path.__file__))
print os.path.dirname
#Returns
"""
<function dirname at 0x00000195E3295E48>
C:\Program Files\Autodesk\3ds Max 2018\python27.zip\ntpath.py
ntpath.py
<function dirname at 0x00000195E3295E48>
"""

 

 

I need to be able to edit the sys.path, get filenames etc as I would normally do with Python external to max or in Maya without this convoluted hassle.

 

os.getcwd() works if I have performed a "save as"  on the script, otherwise, it just prints the location of the last file that was saved via a "save as" option, which is not what is required.

 

I have been developing my script as a .py file but the inability to correctly call os and other python commands is proving a hassle at present.

 

I also get the same issues if I save as a mxs file, so there could be a bug with the environment unless someone has found a way to correctly use the os and sys commands or can show a method that can be used.

 

I tried print pymxs.runtime.getThisScriptFilename() in a py file and an mxs file. Neither worked, just returned None

 

regards

 

 

 

0 Likes
Accepted solutions (2)
3,744 Views
6 Replies
Replies (6)
Message 2 of 7

drew_avis
Autodesk
Autodesk

Hi there, check out the note on this page:

http://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__developer_python_support_in_the_maxscript__htm...

 

"Note: Some special attributes (specifically __file__ and __name__) and source code encoding declarations (\# -*- coding: <encoding name> -*-, defined in PEP 0263) cannot be handled when a script is executed directly from the MAXScript Editor (using Tools > Evaluate All, Ctrl+E) or in the MAXScript Listener. Scripts that use these must be run from the Scripting > Run Script... command to execute properly. The Run Script command runs the file directly in the Python interpreter, while the Evaluate command runs the contents of the file."

 

In short, try running your script using the Run Script command and see if that works for you.

 

Hope that helps,

Drew



Drew Avis
Content Experience Designer
0 Likes
Message 3 of 7

malcomarmstrong
Advocate
Advocate

 

Running it from the scripting menus "Run" does indeed return nearly all the info, except for the sys.argv[0] argument, but it does work when this script is called by Sublime. That's not a big issue as I can get the paths etc that I need from other queries.

 

I noticed that there is no run function in the Run Script dialog for .mxs scripts, why is this?

 

 

I created a.ms file with a python.ExecuteFile command inside and I am now getting the results that I need, though it does seem a long way round to get what is readily available in maya python and python elsewhere. Its more work and boiler plate code that is unnecessary. But, moving forward, which is always good.

 

What I have done is to include a def in the main script that sets the paths I want and it appears to work. Below is the code I used, should anyone wish to use it (if they hadn`t already worked it out!) Cut, paste and save as a .py file named testingOS.py

 

 

import pymxs
import os
import sys
filePaths =[] # list of paths, filenames etc

thisDir = os.getcwd() # OK but defaults to a max install folder.
print "This scripts directory   :", thisDir # OK

def file_info_for_path_updates():    
    s1 = sys.argv[0] # fails here when run from the scripting menu, but is fine in other interpreters
    filePaths.append(s1)
    fileDir = os.path.dirname(__file__)
    filePaths.append(fileDir)
    fileNm = os.path.basename(__file__)
    filePaths.append(fileNm)
    abPth = os.path.dirname(os.path.abspath(__file__))
    filePaths.append(abPth)
    os_cwd = os.getcwd()
    filePaths.append(os_cwd)
    os_parDir = os.path.abspath(os.path.join(os_cwd, os.pardir))
    filePaths.append(os_parDir)
    print "sys.argv[0]              :", s1
    print "File directory           :", fileDir
    print "Filename                 :",fileNm
    print "Absolute path            :", abPth
    print "Current working directory:", os_cwd
    print "Parent Directory         :", os_parDir
    print "Current sys.path:"
    print"\n".join(str(i) for i in sys.path)

    print "\n\nSetting the sys.path to hold the filefolder info for later imports"

    if filePaths[1] not in sys.path:
        sys.path.append(filePaths[1])

    print "Updated sys.path:"
    print"\n".join(str(i) for i in sys.path)
    
    # return filePaths

file_info_for_path_updates()

 

in a Maxscript file (.ms), type the following and save it in the same folder as the .py file above and name it run_testingOS.ms

 

 

thisFile = getFilenamePath(getThisScriptFilename())
clearListener()
python.ExecuteFile(thisFile+"testingOS.py")

With this .ms file tab open, you can now use CTRL+E in the maxscript editor to run the.py file and get back what you need.

 

For what I am doing, I just created a def outside the class and set the paths etc before the main class instance.

 

Perhaps there is a better way, but this works for me and I can continue to develop the code from here. If anyone finds a better way, I would be interested to see it.

 

hope this helps

 

regards

 

 

 

 

 

Message 4 of 7

drew_avis
Autodesk
Autodesk

That's a clever work-around with getting the script path and executing via MAXScript.  Thanks for sharing.

 

Regarding your question about running .mxs scripts from Scripting > Run Script, this extension indicates scripts that are included in other scripts, and not intended to be run stand-alone.  In general, you want to use .ms file extensions for top-level scripts.  I see this isn't indicated in the MXS help, I'll add it.

 

Drew



Drew Avis
Content Experience Designer
0 Likes
Message 5 of 7

malcomarmstrong
Advocate
Advocate

Hi Drew, wondering if you can help me with this, I posted it on another page, but nothing has popped up and I am still trying to decipher the right syntax.

 

What happens (pymxs) when you need to create a command that uses internal commands that have properties such as the code below:

 

Maxscript:

 

addKnot mySplShp mySpln #corner #line myList[1].pos

 

Pymxs (in the context of creating a spline):

 

 

rt.addKnot(mySplShp , mySpln ,"#corner", "#line", myList[0].pos)
-- Runtime error: Invalid knot type: "#corner"

 

Also, "corner", "corner = True", "corner" = True", "#corner:True" and others have not worked yet.

 

So what is the correct call in this case and would this be applicable to any max property that is set with an array item that has a "#" symbol?

 

it seems like it wants an index from an array (due to the option available in max (#corner #Bezier  etc) but I tried that as well

 

Many thanks

0 Likes
Message 6 of 7

drew_avis
Autodesk
Autodesk
Accepted solution

Hi Malcom, for name literals in MAXScript, use pymxs.runtime.name() to access them.  So for example, #corner would be rt.name('corner').  See if that works for you.

 

Drew



Drew Avis
Content Experience Designer
Message 7 of 7

malcomarmstrong
Advocate
Advocate
Accepted solution

Hi Drew, thanks very much for that, it worked and the rest of the code preceding that and after completed as expected.

 

regards

 

 

0 Likes