Skip to content

Commit

Permalink
Merge pull request #555 from Autodesk/sabrih/MAYA-104922/support_pyth…
Browse files Browse the repository at this point in the history
…on3_pxr

Support Python3 for Pixar's UsdMaya and unit tests
  • Loading branch information
Krystian Ligenza authored Jun 15, 2020
2 parents 14e89f9 + 3de5818 commit 1a5d926
Show file tree
Hide file tree
Showing 37 changed files with 228 additions and 167 deletions.
4 changes: 4 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ def PrintError(error):
traceback.print_exc()
print("ERROR:", error)

def Python3():
return sys.version_info.major == 3
############################################################
def Windows():
return platform.system() == "Windows"
Expand Down Expand Up @@ -560,6 +562,7 @@ def __init__(self, args):
Build directory {buildDir}
Install directory {instDir}
Variant {buildVariant}
Python 3: {enablePython3}
Python Debug {debugPython}
CMake generator {cmakeGenerator}"""

Expand Down Expand Up @@ -590,6 +593,7 @@ def __init__(self, args):
ctestArgs=context.ctestArgs,
buildVariant=BuildVariant(context),
debugPython=("On" if context.debugPython else "Off"),
enablePython3=("On" if Python3() else "Off"),
cmakeGenerator=("Default" if not context.cmakeGenerator
else context.cmakeGenerator)
)
Expand Down
47 changes: 33 additions & 14 deletions cmake/modules/FindMaya.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -239,21 +239,7 @@ find_program(MAYA_EXECUTABLE
"Maya's executable path"
)

find_program(MAYA_PY_EXECUTABLE
mayapy
HINTS
"${MAYA_LOCATION}"
"$ENV{MAYA_LOCATION}"
"${MAYA_BASE_DIR}"
PATH_SUFFIXES
Maya.app/Contents/bin/
bin/
DOC
"Maya's Python executable path"
)

if(MAYA_INCLUDE_DIRS AND EXISTS "${MAYA_INCLUDE_DIR}/maya/MTypes.h")

# Tease the MAYA_API_VERSION numbers from the lib headers
file(STRINGS ${MAYA_INCLUDE_DIR}/maya/MTypes.h TMP REGEX "#define MAYA_API_VERSION.*$")
string(REGEX MATCHALL "[0-9]+" MAYA_API_VERSION ${TMP})
Expand All @@ -265,9 +251,42 @@ if(MAYA_INCLUDE_DIRS AND EXISTS "${MAYA_INCLUDE_DIR}/maya/MTypes.h")
else()
string(SUBSTRING ${MAYA_API_VERSION} "0" "4" MAYA_APP_VERSION)
endif()
endif()

# swtich between mayapy and mayapy2
set(mayapy_exe mayapy)
if(${MAYA_APP_VERSION} STRGREATER_EQUAL "2021")
# check to see if we have a mayapy2 executable
find_program(MAYA_PY_EXECUTABLE2
mayapy2
HINTS
"${MAYA_LOCATION}"
"$ENV{MAYA_LOCATION}"
"${MAYA_BASE_DIR}"
PATH_SUFFIXES
Maya.app/Contents/bin/
bin/
DOC
"Maya's Python executable path"
)
if(NOT BUILD_WITH_PYTHON_3 AND MAYA_PY_EXECUTABLE2)
set(mayapy_exe mayapy2)
endif()
endif()

find_program(MAYA_PY_EXECUTABLE
${mayapy_exe}
HINTS
"${MAYA_LOCATION}"
"$ENV{MAYA_LOCATION}"
"${MAYA_BASE_DIR}"
PATH_SUFFIXES
Maya.app/Contents/bin/
bin/
DOC
"Maya's Python executable path"
)

# handle the QUIETLY and REQUIRED arguments and set MAYA_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
Expand Down
10 changes: 9 additions & 1 deletion doc/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Before building the project, consult the following table to ensure you use the r
| Operating System | Windows 10 | Catalina (10.15), Mojave (10.14), High Sierra (10.13) | CentOS 7 |
| Compiler Requirement| Maya 2018/2019 (VS 2015 update 3)<br>Maya 2020 (VS 2017) | Maya 2018/2019 (Xcode 7.3.1)<br>Maya 2020 (Xcode version 10.2.1) | Maya 2018 (gcc 4.8.2)<br>Maya 2019/2020 (gcc 6.3.1) |
| Minimum Cmake Version | 3.13 | 3.13 | 3.13 |
| Python | 2.7.15 | 2.7.15 | 2.7.15 |
| Python | 2.7.15 or 3.7.7 | 2.7.15 or 3.7.7 | 2.7.15 or 3.7.7 |
| Python Packages | PyYAML, PySide, PyOpenGL, Jinja2 | PyYAML, PySide2, PyOpenGL, Jinja2 | PyYAML, PySide, PyOpenGL, Jinja2 |
| Build generator | Visual Studio, Ninja (Recommended) | XCode, Ninja (Recommended) | Ninja (Recommended) |
| Command processor | Visual Studio X64 2015 or 2017 command prompt | bash | bash |
Expand Down Expand Up @@ -186,6 +186,14 @@ Test project /Users/sabrih/Desktop/workspace/build/Debug/plugin/al
100% tests passed, 0 tests failed out of 8
```

***NOTE:*** As part of compatibility support for python 3 in maya-usd, there are number of python tests that require the use of python’s `future` module. While the `future` module is
available in our new preview releases of Maya, this package doesn't exist in the version of python in Maya 2018/2019/2020. Please follow the below steps in order to install the `future` package:

1. Download get-py.py from https://bootstrap.pypa.io/get-pip.py
2. Open a command-line and navigate to `mayapy.exe` for Maya version which needs future package. Run:`mayapy.exe <path_to_downloaded_file>/get-pip.py`
3. Pip will be added to `<path_to_maya>Python/Scripts`
4. Install the future package: `<path_to_maya>Python/Scripts/pip install future`

# Additional Build Instruction

##### Boost:
Expand Down
1 change: 0 additions & 1 deletion plugin/pxr/cmake/macros/Public.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ function(pxr_setup_python)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/__init__.py
${CMAKE_CURRENT_BINARY_DIR}/__init__.pyc
DESTINATION
${INSTALL_DIR_SUFFIX}/${installPrefix}
)
Expand Down
12 changes: 6 additions & 6 deletions plugin/pxr/cmake/macros/compilePython.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import py_compile

if len(sys.argv) < 4:
print "Usage: %s src.py file.py file.pyc" % sys.argv[0]
print("Usage: %s src.py file.py file.pyc" % sys.argv[0])
sys.exit(1)

try:
Expand All @@ -45,14 +45,14 @@
try:
linenumber = exc_value[1][1]
line = exc_value[1][3]
print '%s:%s: %s: "%s"' % (sys.argv[1], linenumber, error, line)
print('%s:%s: %s: "%s"' % (sys.argv[1], linenumber, error, line))
except IndexError:
print '%s: Syntax error: "%s"' % (sys.argv[1], error)
print('%s: Syntax error: "%s"' % (sys.argv[1], error))
else:
print "%s: Unhandled compile error: (%s) %s" % (
sys.argv[1], compileError.exc_type_name, exc_value)
print("%s: Unhandled compile error: (%s) %s" % (
sys.argv[1], compileError.exc_type_name, exc_value))
sys.exit(1)
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
print "%s: Unhandled exception: %s" % (sys.argv[1], exc_value)
print("%s: Unhandled exception: %s" % (sys.argv[1], exc_value))
sys.exit(1)
16 changes: 8 additions & 8 deletions plugin/pxr/cmake/macros/testWrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ def _windowsReplacement(m):

def _cleanOutput(pathPattern, fileName, verbose):
if verbose:
print "stripping path pattern {0} from file {1}".format(pathPattern,
fileName)
print("stripping path pattern {0} from file {1}".format(pathPattern,
fileName))
_stripPath(fileName, pathPattern)
return True

Expand All @@ -137,7 +137,7 @@ def _diff(fileName, baselineDir, verbose):
diff = '/usr/bin/diff'
cmd = [diff, _resolvePath(baselineDir, fileName), fileName]
if verbose:
print "diffing with {0}".format(cmd)
print("diffing with {0}".format(cmd))

# This will print any diffs to stdout which is a nice side-effect
return subprocess.call(cmd) == 0
Expand Down Expand Up @@ -181,7 +181,7 @@ def _runCommand(raw_command, stdout_redir, stderr_redir, env,
cmd = _splitCmd(raw_command)
fout, ferr = _getRedirects(stdout_redir, stderr_redir)
try:
print "cmd: %s" % (cmd, )
print("cmd: %s" % (cmd, ))
retcode = _convertRetCode(subprocess.call(cmd, shell=False, env=env,
stdout=(fout or sys.stdout),
stderr=(ferr or sys.stderr)))
Expand Down Expand Up @@ -217,13 +217,13 @@ def _runCommand(raw_command, stdout_redir, stderr_redir, env,
testDir = tempfile.mkdtemp()
os.chdir(testDir)
if args.verbose:
print "chdir: {0}".format(testDir)
print("chdir: {0}".format(testDir))

# Copy the contents of the testenv directory into our test run directory so
# the test has it's own copy that it can reference and possibly modify.
if args.testenv_dir and os.path.isdir(args.testenv_dir):
if args.verbose:
print "copying testenv dir: {0}".format(args.testenv_dir)
print("copying testenv dir: {0}".format(args.testenv_dir))
try:
_copyTree(args.testenv_dir, os.getcwd())
except Exception as e:
Expand Down Expand Up @@ -273,7 +273,7 @@ def _runCommand(raw_command, stdout_redir, stderr_redir, env,
if args.files_exist:
for f in args.files_exist:
if args.verbose:
print 'checking if {0} exists.'.format(f)
print('checking if {0} exists.'.format(f))
if not os.path.exists(f):
sys.stderr.write('Error: {0} does not exist '
'(FILES_EXIST).'.format(f))
Expand All @@ -282,7 +282,7 @@ def _runCommand(raw_command, stdout_redir, stderr_redir, env,
if args.files_dont_exist:
for f in args.files_dont_exist:
if args.verbose:
print 'checking if {0} does not exist.'.format(f)
print('checking if {0} does not exist.'.format(f))
if os.path.exists(f):
sys.stderr.write('Error: {0} does exist '
'(FILES_DONT_EXIST).'.format(f))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# limitations under the License.
#

from future.utils import iteritems

from pxr import UsdMaya

from pxr import Tf
Expand Down Expand Up @@ -48,7 +50,7 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):
statsOutputLines = []
for profileScopeName, elapsedTime in cls._profileScopeMetrics.iteritems():
for profileScopeName, elapsedTime in iteritems(cls._profileScopeMetrics):
statsDict = {
'profile': profileScopeName,
'metric': 'time',
Expand Down Expand Up @@ -143,7 +145,7 @@ def _RunPlaybackTest(self):
profileScopeName = '%s Proxy Orbit Playback Time' % self._testName

with self._ProfileScope(profileScopeName):
for frame in xrange(int(self.animStartTime), int(self.animEndTime + 1.0)):
for frame in range(int(self.animStartTime), int(self.animEndTime + 1.0)):
cmds.currentTime(frame, edit=True)

playElapsedTime = self._profileScopeMetrics[profileScopeName]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# limitations under the License.
#

from future.utils import iteritems

from pxr import UsdMaya

from pxr import Tf
Expand Down Expand Up @@ -46,7 +48,7 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):
statsOutputLines = []
for profileScopeName, elapsedTime in cls._profileScopeMetrics.iteritems():
for profileScopeName, elapsedTime in iteritems(cls._profileScopeMetrics):
statsDict = {
'profile': profileScopeName,
'metric': 'time',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# limitations under the License.
#

from future.utils import iteritems

from pxr import UsdMaya

from pxr import Gf
Expand Down Expand Up @@ -110,7 +112,7 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):
statsOutputLines = []
for profileScopeName, elapsedTime in cls._profileScopeMetrics.iteritems():
for profileScopeName, elapsedTime in iteritems(cls._profileScopeMetrics):
statsDict = {
'profile': profileScopeName,
'metric': 'time',
Expand Down
4 changes: 2 additions & 2 deletions plugin/pxr/maya/lib/pxrUsdMayaGL/testenv/testPxrUsdMayaGL.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ def testSimpleSceneDrawsAndReloads(self):
# a memory issue would sometimes cause maya to crash when opening a new
# scene.

for _ in xrange(20):
for _ in range(20):
cmds.file(new=True, force=True)
for i in xrange(10):
for i in range(10):
usdFilePath = os.path.abspath('plane%d.usda' % (i%2))
assembly = cmds.assembly(name='plane', type='pxrUsdReferenceAssembly')
cmds.setAttr("%s.filePath" % assembly, usdFilePath, type='string')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def variantSets_Replace(nodeAttr, new):

try:
cmds.optionMenuGrp(omg, e=True, value=variantOverride)
except RuntimeError, e:
except (RuntimeError, e):
cmds.warning('Invalid choice %r for %r'%(variantOverride, variantSetName))

cmds.optionMenuGrp(omg, e=True, changeCommand=functools.partial(variantSets_changeCommmand, omg=omg, node=node, variantSetName=variantSetName))
Expand Down
2 changes: 1 addition & 1 deletion plugin/pxr/maya/lib/usdMaya/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def LoadReferenceAssemblies(parentNodes=None):
isInterruptable=True, minValue=0, maxValue=numRefAssemblies,
status='Loading USD reference assemblies...')

for i in xrange(numRefAssemblies):
for i in range(numRefAssemblies):
refAssembly = refAssemblies[i]

if mainProgressBar:
Expand Down
8 changes: 4 additions & 4 deletions plugin/pxr/maya/lib/usdMaya/testenv/testUsdExportAsClip.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def setUpClass(cls):

cmds.file(os.path.abspath('UsdExportAsClipTest.ma'), open=True,
force=True)
print os.path.abspath('UsdExportAsClipTest.ma')
print(os.path.abspath('UsdExportAsClipTest.ma'))

cmds.loadPlugin('pxrUsd', quiet=True)

Expand All @@ -55,9 +55,9 @@ def getValues(stage):
cube = stage.GetPrimAtPath(primPath)
self.assertTrue(cube)
attr = cube.GetAttribute(attrName)
return [attr.Get(time=tc) for tc in xrange(*frameRange)]
return [attr.Get(time=tc) for tc in range(*frameRange)]

for frame, x,y in zip(xrange(*frameRange),
for frame, x,y in zip(range(*frameRange),
getValues(canonicalStage),
getValues(testStage)):
msg = ('different values found on frame: {frame}\n'
Expand Down Expand Up @@ -116,7 +116,7 @@ def testExportAsClip(self):
canonicalUsdFile = os.path.abspath('canonical.usda')
cmds.usdExport(mergeTransformAndShape=True, file=canonicalUsdFile, frameRange=(1, 20))

print 'comparing: \nnormal: {}\nstitched: {}'.format(canonicalUsdFile, stitchedPath)
print('comparing: \nnormal: {}\nstitched: {}'.format(canonicalUsdFile, stitchedPath))
canonicalStage = Usd.Stage.Open(canonicalUsdFile)
clipsStage = Usd.Stage.Open(stitchedPath)
# visible
Expand Down
4 changes: 2 additions & 2 deletions plugin/pxr/maya/lib/usdMaya/testenv/testUsdExportColorSets.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,15 +369,15 @@ def _GetExpectedColorSetIndices(self, colorSetName):
else:
# Every component has an assignment.
if isFaceColor:
assignmentIndices = [i for i in xrange(self._colorSetSourceMesh.numPolygons())]
assignmentIndices = [i for i in range(self._colorSetSourceMesh.numPolygons())]
elif isVertexColor:
# The assignments for vertex color are a little different
# due to MItMeshFaceVertex visiting components in faceVertex
# order, in which case we actually visit vertices somewhat
# out of order.
assignmentIndices = [0, 1, 3, 2, 5, 4, 7, 6]
elif isFaceVertexColor:
assignmentIndices = [i for i in xrange(self._colorSetSourceMesh.numFaceVertices())]
assignmentIndices = [i for i in range(self._colorSetSourceMesh.numFaceVertices())]

return assignmentIndices

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# limitations under the License.
#

from future.utils import iteritems

import os
import unittest

Expand Down Expand Up @@ -44,9 +46,9 @@ def assertRotateSamples(self, usdFile, expected):
xform = stage.GetPrimAtPath('/pCube1')
rot = xform.GetProperty('xformOp:rotateXYZ')

for time, expectedVec in expected.iteritems():
for time, expectedVec in iteritems(expected):
actualVec = rot.Get(time)
for i in xrange(3):
for i in range(3):
msg = "sample at time {}, index {} unequal".format(time, i)
self.assertAlmostEqual(actualVec[i], expectedVec[i], 4, msg)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# limitations under the License.
#

from future.utils import iteritems

import os
import unittest

Expand Down Expand Up @@ -91,8 +93,8 @@ def doExportImportOneMethod(self, method, constraint=True, place3d=True,
if filter:
options['filterTypes'] = ','.join(filter)
kwargs['options'] = ';'.join('{}={}'.format(key, val)
for key, val in options.iteritems())
print "running: {}(*{!r}, **{!r})".format(exportMethod.__name__, args, kwargs)
for key, val in iteritems(options))
print("running: {}(*{!r}, **{!r})".format(exportMethod.__name__, args, kwargs))
exportMethod(*args, **kwargs)
return Usd.Stage.Open(usdFile)

Expand Down
Loading

0 comments on commit 1a5d926

Please sign in to comment.