MSyntax.enableQuery() and MSyntax.enableEdit() Break Object Parsing

In Maya, many built-in commands support any of three modes: create, edit, and query. Although it may not be immediately obvious, each of these modes has some particularities that set them apart, and which consequently require some extra effort on the part of the programmer to support. Maya does have some built-in support, which is presently only partially functional, so it is helpful to understand what it actually gains you to use it and work around its issues.

Consider the polySphere command in MEL as an example:

Create Mode:

polySphere -n "newSphere" -r 5;
polySphere -n "otherSphere" -r 2;

This creates two polygon sphere objects with the specified radii.

Edit Mode:

polySphere -e -r 1 newSphere otherSphere;

Try though you might, edit mode only works on one object at a time. In this case, the edit will only be applied to newSphere.

Query Mode:

polySphere -q -r newSphere otherSphere;

Just as is the case in edit mode, trying to specify multiple objects does not work—you can only query one object and one attribute at a time. Moreover, while the -r flag typically requires a decimal number, it requires no argument in query mode.

Fundamentally then, you as a programmer have two somewhat tedious problems to solve:

  1. How do I make my command throw an error in create/edit modes when there is no argument specified, but not in query mode?
  2. How do I make my command require an object in edit and query modes, but not in create mode?

In Complete Maya Programming, David Gould writes:

The various modes are simply a convention used to describe when certain operations can and can’t be performed. Since the operations of creating, editing, and querying are so common, they have been given their own convention that all commands should follow. The standard convention is that if a command supports querying and editing, it adds the query and edit flags. These are defined in their short and long forms as -q/query and -e/edit, respectively. (334-335)

Though this may have been the case at the time that Gould wrote, the API has included special functions for dealing with these modes at least as far back as version 8.5, so they are accessible to Python in all versions with official support. Specifically, the API includes MSyntax.enableQuery() and MSyntax.enableEdit() as part of the syntax definition. Calling these functions in the syntax creator does a couple of things:

  1. Automatically adds the edit/query flags to the syntax definition, consequently permitting the use of the MArgParser.isEdit() and MArgParser.isQuery() functions
  2. Automatically handles problem number 1 above by throwing descriptive errors when constructing the MArgDatabase object using the custom syntax

However, there are a couple of problems. Typically, you can rely on your MArgDatabase construction to catch a variety of syntax errors and provide the user with valuable information. For example, you can specify a minimum number of objects in your syntax creator that your command requires:

syntax.setObjectType(OM.MSyntax.kSelectionList, 1) # the command requires a minimum of 1 object

Using this function call, you can reliably parse arguments in your doIt() function like this:

try:
    argData = OM.MArgDatabase(self.syntax(), args) # if this fails, it will raise its own exception...
except:
    pass # ...so we can just pass here
else:
    # Do cool stuff here

…and get a descriptive error message in MEL like this if you try to invoke the command without supplying any objects:

// Error: line 1: This command requires at least 1 argument(s) to be specified or selected;  found 0. //

If you try to implement edit and query modes fully manually, as David Gould suggests, then this same technique still works. However, if you use MSyntax.enableQuery() or MSyntax.enableEdit() to add these modes, then they will not respect your minimum object requirements! You can therefore run into problems where your command tries to work with an object in the selection list, but it does not exist because Maya’s built-in error-trapping did not catch the problem. Consequently, you need to add an additional, manual check when you parse your arguments. It could look something like this:

# parse the arguments
try:
	argData = OM.MArgDatabase(self.syntax(), args) # if this fails, it will raise its own exception...
except:
	pass # ...so we can just pass here
else:
	# manually confirm the object list
	sList = OM.MSelectionList()
	argData.getObjects(sList)
	if (argData.isEdit() or argData.isQuery()) and sList.length() is not 1:
		sys.stderr.write ("ERROR: This command requires exactly 1 argument to be specified or selected;  found 0.")
		sys.exit()
	# Do cool stuff here

In the end, there is (at least presently) still some manual work required, though these simple function calls do go some way in helping you easily support additional command modes.

Presently, the Command Engine only throws descriptive syntax errors when a command is invoked from MEL. Invoking with a syntax error from Python simply prints no message, though the dysfunction will be contained.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.