Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2445 from BigRoy/maya_py3_compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
mkolar authored Feb 25, 2022
2 parents b8f3d8b + 4d8afc6 commit 8b58c2c
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 56 deletions.
57 changes: 34 additions & 23 deletions openpype/hosts/maya/api/customize.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from functools import partial

import maya.cmds as mc
import maya.cmds as cmds
import maya.mel as mel

from openpype.api import resources
Expand All @@ -30,9 +30,9 @@ def override_component_mask_commands():
log.info("Installing override_component_mask_commands..")

# Get all object mask buttons
buttons = mc.formLayout("objectMaskIcons",
query=True,
childArray=True)
buttons = cmds.formLayout("objectMaskIcons",
query=True,
childArray=True)
# Skip the triangle list item
buttons = [btn for btn in buttons if btn != "objPickMenuLayout"]

Expand All @@ -43,14 +43,14 @@ def on_changed_callback(raw_command, state):
# toggle the others based on whether any of the buttons
# was remaining active after the toggle, if not then
# enable all
if mc.getModifiers() == 4: # = CTRL
if cmds.getModifiers() == 4: # = CTRL
state = True
active = [mc.iconTextCheckBox(btn, query=True, value=True) for btn
in buttons]
active = [cmds.iconTextCheckBox(btn, query=True, value=True)
for btn in buttons]
if any(active):
mc.selectType(allObjects=False)
cmds.selectType(allObjects=False)
else:
mc.selectType(allObjects=True)
cmds.selectType(allObjects=True)

# Replace #1 with the current button state
cmd = raw_command.replace(" #1", " {}".format(int(state)))
Expand All @@ -63,13 +63,13 @@ def on_changed_callback(raw_command, state):
# try to implement the fix. (This also allows us to
# "uninstall" the behavior later)
if btn not in COMPONENT_MASK_ORIGINAL:
original = mc.iconTextCheckBox(btn, query=True, cc=True)
original = cmds.iconTextCheckBox(btn, query=True, cc=True)
COMPONENT_MASK_ORIGINAL[btn] = original

# Assign the special callback
original = COMPONENT_MASK_ORIGINAL[btn]
new_fn = partial(on_changed_callback, original)
mc.iconTextCheckBox(btn, edit=True, cc=new_fn)
cmds.iconTextCheckBox(btn, edit=True, cc=new_fn)


def override_toolbox_ui():
Expand All @@ -78,25 +78,36 @@ def override_toolbox_ui():
parent_widget = get_main_window()

# Ensure the maya web icon on toolbox exists
web_button = "ToolBox|MainToolboxLayout|mayaWebButton"
if not mc.iconTextButton(web_button, query=True, exists=True):
button_names = [
# Maya 2022.1+ with maya.cmds.iconTextStaticLabel
"ToolBox|MainToolboxLayout|mayaHomeToolboxButton",
# Older with maya.cmds.iconTextButton
"ToolBox|MainToolboxLayout|mayaWebButton"
]
for name in button_names:
if cmds.control(name, query=True, exists=True):
web_button = name
break
else:
# Button does not exist
log.warning("Can't find Maya Home/Web button to override toolbox ui..")
return

mc.iconTextButton(web_button, edit=True, visible=False)
cmds.control(web_button, edit=True, visible=False)

# real = 32, but 36 with padding - according to toolbox mel script
icon_size = 36
parent = web_button.rsplit("|", 1)[0]

# Ensure the parent is a formLayout
if not mc.objectTypeUI(parent) == "formLayout":
if not cmds.objectTypeUI(parent) == "formLayout":
return

# Create our controls
controls = []

controls.append(
mc.iconTextButton(
cmds.iconTextButton(
"pype_toolbox_lookmanager",
annotation="Look Manager",
label="Look Manager",
Expand All @@ -109,7 +120,7 @@ def override_toolbox_ui():
)

controls.append(
mc.iconTextButton(
cmds.iconTextButton(
"pype_toolbox_workfiles",
annotation="Work Files",
label="Work Files",
Expand All @@ -124,7 +135,7 @@ def override_toolbox_ui():
)

controls.append(
mc.iconTextButton(
cmds.iconTextButton(
"pype_toolbox_loader",
annotation="Loader",
label="Loader",
Expand All @@ -139,7 +150,7 @@ def override_toolbox_ui():
)

controls.append(
mc.iconTextButton(
cmds.iconTextButton(
"pype_toolbox_manager",
annotation="Inventory",
label="Inventory",
Expand All @@ -159,7 +170,7 @@ def override_toolbox_ui():
for i, control in enumerate(controls):
previous = controls[i - 1] if i > 0 else web_button

mc.formLayout(parent, edit=True,
attachControl=[control, "bottom", 0, previous],
attachForm=([control, "left", 1],
[control, "right", 1]))
cmds.formLayout(parent, edit=True,
attachControl=[control, "bottom", 0, previous],
attachForm=([control, "left", 1],
[control, "right", 1]))
80 changes: 68 additions & 12 deletions openpype/hosts/maya/api/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import json
import logging
import itertools
import contextlib
from collections import OrderedDict, defaultdict
from math import ceil
Expand Down Expand Up @@ -267,8 +266,10 @@ def float_round(num, places=0, direction=ceil):

def pairwise(iterable):
"""s -> (s0,s1), (s2,s3), (s4, s5), ..."""
from six.moves import zip

a = iter(iterable)
return itertools.izip(a, a)
return zip(a, a)


def export_alembic(nodes,
Expand Down Expand Up @@ -2986,19 +2987,40 @@ def set_colorspace():
"""
project_name = os.getenv("AVALON_PROJECT")
imageio = get_anatomy_settings(project_name)["imageio"]["maya"]
root_dict = imageio["colorManagementPreference"]

# Maya 2022+ introduces new OCIO v2 color management settings that
# can override the old color managenement preferences. OpenPype has
# separate settings for both so we fall back when necessary.
use_ocio_v2 = imageio["colorManagementPreference_v2"]["enabled"]
required_maya_version = 2022
maya_version = int(cmds.about(version=True))
maya_supports_ocio_v2 = maya_version >= required_maya_version
if use_ocio_v2 and not maya_supports_ocio_v2:
# Fallback to legacy behavior with a warning
log.warning("Color Management Preference v2 is enabled but not "
"supported by current Maya version: {} (< {}). Falling "
"back to legacy settings.".format(
maya_version, required_maya_version)
)
use_ocio_v2 = False

if use_ocio_v2:
root_dict = imageio["colorManagementPreference_v2"]
else:
root_dict = imageio["colorManagementPreference"]

if not isinstance(root_dict, dict):
msg = "set_colorspace(): argument should be dictionary"
log.error(msg)

log.debug(">> root_dict: {}".format(root_dict))

# first enable color management
# enable color management
cmds.colorManagementPrefs(e=True, cmEnabled=True)
cmds.colorManagementPrefs(e=True, ocioRulesEnabled=True)

# second set config path
# set config path
custom_ocio_config = False
if root_dict.get("configFilePath"):
unresolved_path = root_dict["configFilePath"]
ocio_paths = unresolved_path[platform.system().lower()]
Expand All @@ -3015,16 +3037,50 @@ def set_colorspace():
cmds.colorManagementPrefs(e=True, cmConfigFileEnabled=True)
log.debug("maya '{}' changed to: {}".format(
"configFilePath", resolved_path))
root_dict.pop("configFilePath")
custom_ocio_config = True
else:
cmds.colorManagementPrefs(e=True, cmConfigFileEnabled=False)
cmds.colorManagementPrefs(e=True, configFilePath="" )
cmds.colorManagementPrefs(e=True, configFilePath="")

# If no custom OCIO config file was set we make sure that Maya 2022+
# either chooses between Maya's newer default v2 or legacy config based
# on OpenPype setting to use ocio v2 or not.
if maya_supports_ocio_v2 and not custom_ocio_config:
if use_ocio_v2:
# Use Maya 2022+ default OCIO v2 config
log.info("Setting default Maya OCIO v2 config")
cmds.colorManagementPrefs(edit=True, configFilePath="")
else:
# Set the Maya default config file path
log.info("Setting default Maya OCIO v1 legacy config")
cmds.colorManagementPrefs(edit=True, configFilePath="legacy")

# third set rendering space and view transform
renderSpace = root_dict["renderSpace"]
cmds.colorManagementPrefs(e=True, renderingSpaceName=renderSpace)
viewTransform = root_dict["viewTransform"]
cmds.colorManagementPrefs(e=True, viewTransformName=viewTransform)
# set color spaces for rendering space and view transforms
def _colormanage(**kwargs):
"""Wrapper around `cmds.colorManagementPrefs`.
This logs errors instead of raising an error so color management
settings get applied as much as possible.
"""
assert len(kwargs) == 1, "Must receive one keyword argument"
try:
cmds.colorManagementPrefs(edit=True, **kwargs)
log.debug("Setting Color Management Preference: {}".format(kwargs))
except RuntimeError as exc:
log.error(exc)

if use_ocio_v2:
_colormanage(renderingSpaceName=root_dict["renderSpace"])
_colormanage(displayName=root_dict["displayName"])
_colormanage(viewName=root_dict["viewName"])
else:
_colormanage(renderingSpaceName=root_dict["renderSpace"])
if maya_supports_ocio_v2:
_colormanage(viewName=root_dict["viewTransform"])
_colormanage(displayName="legacy")
else:
_colormanage(viewTransformName=root_dict["viewTransform"])


@contextlib.contextmanager
Expand Down
11 changes: 4 additions & 7 deletions openpype/hosts/maya/plugins/create/create_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ def _create_render_settings(self):
# get pools
pool_names = []

self.server_aliases = self.deadline_servers.keys()
self.server_aliases = list(self.deadline_servers.keys())
self.data["deadlineServers"] = self.server_aliases
self.data["suspendPublishJob"] = False
self.data["review"] = True
Expand Down Expand Up @@ -286,15 +286,12 @@ def _create_render_settings(self):
raise RuntimeError("Both Deadline and Muster are enabled")

if deadline_enabled:
# if default server is not between selected, use first one for
# initial list of pools.
try:
deadline_url = self.deadline_servers["default"]
except KeyError:
deadline_url = [
self.deadline_servers[k]
for k in self.deadline_servers.keys()
][0]
# if 'default' server is not between selected,
# use first one for initial list of pools.
deadline_url = next(iter(self.deadline_servers.values()))

pool_names = self._get_deadline_pools(deadline_url)

Expand Down
2 changes: 1 addition & 1 deletion openpype/hosts/maya/plugins/publish/collect_look.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ def collect(self, instance):

# Collect file nodes used by shading engines (if we have any)
files = []
look_sets = sets.keys()
look_sets = list(sets.keys())
shader_attrs = [
"surfaceShader",
"volumeShader",
Expand Down
5 changes: 3 additions & 2 deletions openpype/hosts/maya/plugins/publish/collect_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,14 @@ def process(self, context):
publish_meta_path = None
for aov in exp_files:
full_paths = []
for file in aov[aov.keys()[0]]:
aov_first_key = list(aov.keys())[0]
for file in aov[aov_first_key]:
full_path = os.path.join(workspace, default_render_file,
file)
full_path = full_path.replace("\\", "/")
full_paths.append(full_path)
publish_meta_path = os.path.dirname(full_path)
aov_dict[aov.keys()[0]] = full_paths
aov_dict[aov_first_key] = full_paths

frame_start_render = int(self.get_render_attribute(
"startFrame", layer=layer_name))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ def grouper(iterable, n, fillvalue=None):
"""
args = [iter(iterable)] * n
return itertools.izip_longest(fillvalue=fillvalue, *args)
from six.moves import zip_longest
return zip_longest(fillvalue=fillvalue, *args)


def unlock(plug):
Expand Down
8 changes: 7 additions & 1 deletion openpype/hosts/maya/plugins/publish/extract_look.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import sys
import json
import tempfile
import platform
import contextlib
import subprocess
from collections import OrderedDict
Expand Down Expand Up @@ -62,6 +63,11 @@ def maketx(source, destination, *args):
from openpype.lib import get_oiio_tools_path

maketx_path = get_oiio_tools_path("maketx")

if platform.system().lower() == "windows":
# Ensure .exe extension
maketx_path += ".exe"

if not os.path.exists(maketx_path):
print(
"OIIO tool not found in {}".format(maketx_path))
Expand Down Expand Up @@ -216,7 +222,7 @@ def process(self, instance):
self.log.info("Extract sets (%s) ..." % _scene_type)
lookdata = instance.data["lookData"]
relationships = lookdata["relationships"]
sets = relationships.keys()
sets = list(relationships.keys())
if not sets:
self.log.info("No sets found")
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ def maya_is_true(self, attr_val):
Maya API will return a list of values, which need to be properly
handled to evaluate properly.
"""
if isinstance(attr_val, types.BooleanType):
if isinstance(attr_val, bool):
return attr_val
elif isinstance(attr_val, (types.ListType, types.GeneratorType)):
elif isinstance(attr_val, (list, types.GeneratorType)):
return any(attr_val)
else:
return bool(attr_val)
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import maya.api.OpenMaya as om
import pymel.core as pm

from six.moves import xrange


class GetOverlappingUVs(object):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ def maya_is_true(attr_val):
bool: cast Maya attribute to Pythons boolean value.
"""
if isinstance(attr_val, types.BooleanType):
if isinstance(attr_val, bool):
return attr_val
elif isinstance(attr_val, (types.ListType, types.GeneratorType)):
elif isinstance(attr_val, (list, types.GeneratorType)):
return any(attr_val)
else:
return bool(attr_val)
Loading

0 comments on commit 8b58c2c

Please sign in to comment.