pymxs
ModuleThe pymxs module provides access to the MAXScript runtime, as well as some top-level functions and types. This topic covers those top-level members:
pymxs.runtime
pymxs.animate
run_undo()
and run_redo()
pymxs.print_()
functionpymxs.byref()
function, to handle those situations where a MAXScript function takes a by-reference parameterpymxs.mxstoken()
function, to handle access to pymxs.runtime in multi-threaded situationspymxs.run_undo()
and pymxs.run_redo()
pymxs.mxstoken()
pymxs.runtime
This member exposes the MAXScript runtime, and all the global symbols it contains, to Python scripts. The runtime is dynamic, so global objects created in MAXScript are subsequently available to pymxs.runtime
.
The names of objects available in the pymxs.runtime
module correspond to MAXScript globals. So, for example, to create a teapot you can use the MAXScript Teapot()
constructor like this:
>>> import pymxs
>>> rt = pymxs.runtime
>>> t = rt.Teapot()
>>> rt.classOf(t)
<GeometryClass<Teapot>>
Several MAXScript "context expressions" are exposed to pymxs via top-level functions. These members are:
pymxs.animate(True|False)
pymxs.attime(True|False)
pymxs.atlevel(True|False)
pymxs.quiet(True|False)
pymxs.redraw(True|False)
pymxs.undo(True|False)
the following MAXScript context expressions are not available in pymxs: coordsys
, about
, printAllElements
, defaultAction
, MXSCallstackCaptureEnabled
, dontRepeatMessages
, and macroRecorderEmitterEnabled
. For coordsys
, you can achieve the same effect by changing the current coordinate system using pymxs.runtime.setRefCoordSys(mode_name)
.
In MAXScript, a context expression is used in a scoped code block, for example:
t = teapot()
with animate on
(
at time 0 t.position = [-100, 0, 0]
at time 100 t.position = [100, 0, 0]
)
Here, the with animate
context applies to the code block, while the at time
context applies to each statement. Note that the with
is optional in MAXScript, and you often do not see it used.
In pymxs we would do something similar by scoping using the Python with
statement:
import pymxs
rt = pymxs.runtime
t = rt.Teapot()
with pymxs.animate(True):
with pymxs.attime(0):
t.pos = rt.Point3(-100, 0, 0)
with pymxs.attime(100):
t.pos = rt.Point3(100, 0, 0)
pymxs.run_undo()
and pymxs.run_redo()
pymxs.undo(True|False)
pymxs.run_undo()
pymxs.run_redo()
Most 3ds Max Commands (those invoked by max ...
) are not directly available in pymxs.runtime (see the pymxs Limitations and Workarounds topic). However, the two functions pymxs.run_undo()
and pymxs.run_redo()
are mapped to max undo
and max redo
respectively to provide direct access to these commands.
As with MAXScript, operations run through pymxs are not recorded by the undo system. Undo must be specifically enabled. Undoable pymxs operations appear as items labeled MAXScript in the 3ds Max Undo menu.
For example, to create a teapot, change its position, and then undo the change:
import pymxs
rt = pymxs.runtime
# this will not be undoable:
with pymxs.undo(False):
t = rt.Teapot()
with pymxs.undo(True):
t.pos = rt.Point3(20,20,20)
pymxs.run_undo() # undo the position assignment to [20,20,20]
pymxs.run_redo() # redo the position assignement to [20,20,20]
The way an undo block in pymxs handles exceptions is different than in MAXScript. When an exception is raised, code executed before the exception is undone. The exception is not raised beyond the scope of the undo block, as the undo operation is considered to be the exception handler. Here is an example to illustrate this behavior:
# undo with exception
import pymxs
from pymxs import runtime as rt
def make_box_and_raise():
with pymxs.undo(True, 'Making box'):
rt.Box()
# this will undo the box, and the error will not show up
# in the listener, because it is handled:
raise RuntimeError('This is an error')
def make_sphere_and_raise():
rt.Sphere()
# this will show up in the lister as an unhandled exception
raise RuntimeError('This is an error')
make_box_and_raise()
make_sphere_and_raise()
pymxs.print_(msg[, isErr[, [forceOnMainThread]])
This member gives you more control over error formatting and threading behavior.
msg
- the string to print. isErr
- an optional boolean that indicates whether the message should be formatted as an error (in red, by default). The default is False.forceOnMainThread
- an optional boolean that indicates whether the print should happen on the main thread. In a threaded script, setting this to True ensures that output is sent to the Listener window even if called from a worker thread. If False, when called from a worker thread, output is sent to stdout/stderr (the 3dsmax_ouput.log file or console). The default is True.This function exists because both MAXScript print()
and assert()
functions are disabled and not callable from pymxs.runtime
. There are a couple of ways to work around this limitation to send messages to the Listener window. The simplest is to use the standard Python print()
function and assert
statement. However, you cannot control formatting or threading behavior with these functions, so there may be situations where pymxs.print_()
is the better solution.
The pymxs.byref()
function allows you to use MAXScript functions that take "by reference" parameters. See the By-Reference Parameter Handling in pymxs topic for more information.
As of 3ds Max 2021, the pymxs.mxsreference()
function is marked as deprecated, and will produce a warning in the Listener window when called the first time. Use pymxs.byref()
instead.
pymxs.mxstoken()
pymxs.mxstoken()
You cannot call pymxs.runtime commands directly on a worker thread, as this will cause a runtime exception. However, pymxs has a mxstoken()
function to support multi-threading by providing a synchronization mechanism between worker threads.
For an example of this approach, see the example \<maxdirectory>\scripts\Python\demoMXSToken.py.