[Automated] Merged develop into main

This commit is contained in:
pypebot 2022-10-12 06:05:26 +02:00 committed by GitHub
commit 0d1aea447f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 499 additions and 144 deletions

View file

@ -2,6 +2,7 @@ from .mongo import get_project_connection
from .entities import ( from .entities import (
get_assets, get_assets,
get_asset_by_id, get_asset_by_id,
get_version_by_id,
get_representation_by_id, get_representation_by_id,
convert_id, convert_id,
) )
@ -127,12 +128,20 @@ def get_linked_representation_id(
if not version_id: if not version_id:
return [] return []
version_doc = get_version_by_id(
project_name, version_id, fields=["type", "version_id"]
)
if version_doc["type"] == "hero_version":
version_id = version_doc["version_id"]
if max_depth is None: if max_depth is None:
max_depth = 0 max_depth = 0
match = { match = {
"_id": version_id, "_id": version_id,
"type": {"$in": ["version", "hero_version"]} # Links are not stored to hero versions at this moment so filter
# is limited to just versions
"type": "version"
} }
graph_lookup = { graph_lookup = {
@ -187,7 +196,7 @@ def _process_referenced_pipeline_result(result, link_type):
referenced_version_ids = set() referenced_version_ids = set()
correctly_linked_ids = set() correctly_linked_ids = set()
for item in result: for item in result:
input_links = item["data"].get("inputLinks") input_links = item.get("data", {}).get("inputLinks")
if not input_links: if not input_links:
continue continue
@ -203,7 +212,7 @@ def _process_referenced_pipeline_result(result, link_type):
continue continue
for output in sorted(outputs_recursive, key=lambda o: o["depth"]): for output in sorted(outputs_recursive, key=lambda o: o["depth"]):
output_links = output["data"].get("inputLinks") output_links = output.get("data", {}).get("inputLinks")
if not output_links: if not output_links:
continue continue

View file

@ -23,6 +23,7 @@ CURRENT_PROJECT_CONFIG_SCHEMA = "openpype:config-2.0"
CURRENT_ASSET_DOC_SCHEMA = "openpype:asset-3.0" CURRENT_ASSET_DOC_SCHEMA = "openpype:asset-3.0"
CURRENT_SUBSET_SCHEMA = "openpype:subset-3.0" CURRENT_SUBSET_SCHEMA = "openpype:subset-3.0"
CURRENT_VERSION_SCHEMA = "openpype:version-3.0" CURRENT_VERSION_SCHEMA = "openpype:version-3.0"
CURRENT_HERO_VERSION_SCHEMA = "openpype:hero_version-1.0"
CURRENT_REPRESENTATION_SCHEMA = "openpype:representation-2.0" CURRENT_REPRESENTATION_SCHEMA = "openpype:representation-2.0"
CURRENT_WORKFILE_INFO_SCHEMA = "openpype:workfile-1.0" CURRENT_WORKFILE_INFO_SCHEMA = "openpype:workfile-1.0"
CURRENT_THUMBNAIL_SCHEMA = "openpype:thumbnail-1.0" CURRENT_THUMBNAIL_SCHEMA = "openpype:thumbnail-1.0"
@ -162,6 +163,34 @@ def new_version_doc(version, subset_id, data=None, entity_id=None):
} }
def new_hero_version_doc(version_id, subset_id, data=None, entity_id=None):
"""Create skeleton data of hero version document.
Args:
version_id (ObjectId): Is considered as unique identifier of version
under subset.
subset_id (Union[str, ObjectId]): Id of parent subset.
data (Dict[str, Any]): Version document data.
entity_id (Union[str, ObjectId]): Predefined id of document. New id is
created if not passed.
Returns:
Dict[str, Any]: Skeleton of version document.
"""
if data is None:
data = {}
return {
"_id": _create_or_convert_to_mongo_id(entity_id),
"schema": CURRENT_HERO_VERSION_SCHEMA,
"type": "hero_version",
"version_id": version_id,
"parent": subset_id,
"data": data
}
def new_representation_doc( def new_representation_doc(
name, version_id, context, data=None, entity_id=None name, version_id, context, data=None, entity_id=None
): ):
@ -293,6 +322,20 @@ def prepare_version_update_data(old_doc, new_doc, replace=True):
return _prepare_update_data(old_doc, new_doc, replace) return _prepare_update_data(old_doc, new_doc, replace)
def prepare_hero_version_update_data(old_doc, new_doc, replace=True):
"""Compare two hero version documents and prepare update data.
Based on compared values will create update data for 'UpdateOperation'.
Empty output means that documents are identical.
Returns:
Dict[str, Any]: Changes between old and new document.
"""
return _prepare_update_data(old_doc, new_doc, replace)
def prepare_representation_update_data(old_doc, new_doc, replace=True): def prepare_representation_update_data(old_doc, new_doc, replace=True):
"""Compare two representation documents and prepare update data. """Compare two representation documents and prepare update data.

View file

@ -6,9 +6,9 @@ from xml.etree import ElementTree as ET
from Qt import QtCore, QtWidgets from Qt import QtCore, QtWidgets
import openpype.api as openpype
import qargparse import qargparse
from openpype import style from openpype import style
from openpype.settings import get_current_project_settings
from openpype.lib import Logger from openpype.lib import Logger
from openpype.pipeline import LegacyCreator, LoaderPlugin from openpype.pipeline import LegacyCreator, LoaderPlugin
@ -306,7 +306,7 @@ class Creator(LegacyCreator):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Creator, self).__init__(*args, **kwargs) super(Creator, self).__init__(*args, **kwargs)
self.presets = openpype.get_current_project_settings()[ self.presets = get_current_project_settings()[
"flame"]["create"].get(self.__class__.__name__, {}) "flame"]["create"].get(self.__class__.__name__, {})
# adding basic current context flame objects # adding basic current context flame objects

View file

@ -3,8 +3,6 @@ import sys
import re import re
import contextlib import contextlib
from Qt import QtGui
from openpype.lib import Logger from openpype.lib import Logger
from openpype.client import ( from openpype.client import (
get_asset_by_name, get_asset_by_name,
@ -92,7 +90,7 @@ def set_asset_resolution():
}) })
def validate_comp_prefs(comp=None): def validate_comp_prefs(comp=None, force_repair=False):
"""Validate current comp defaults with asset settings. """Validate current comp defaults with asset settings.
Validates fps, resolutionWidth, resolutionHeight, aspectRatio. Validates fps, resolutionWidth, resolutionHeight, aspectRatio.
@ -135,21 +133,22 @@ def validate_comp_prefs(comp=None):
asset_value = asset_data[key] asset_value = asset_data[key]
comp_value = comp_frame_format_prefs.get(comp_key) comp_value = comp_frame_format_prefs.get(comp_key)
if asset_value != comp_value: if asset_value != comp_value:
# todo: Actually show dialog to user instead of just logging
log.warning(
"Comp {pref} {value} does not match asset "
"'{asset_name}' {pref} {asset_value}".format(
pref=label,
value=comp_value,
asset_name=asset_doc["name"],
asset_value=asset_value)
)
invalid_msg = "{} {} should be {}".format(label, invalid_msg = "{} {} should be {}".format(label,
comp_value, comp_value,
asset_value) asset_value)
invalid.append(invalid_msg) invalid.append(invalid_msg)
if not force_repair:
# Do not log warning if we force repair anyway
log.warning(
"Comp {pref} {value} does not match asset "
"'{asset_name}' {pref} {asset_value}".format(
pref=label,
value=comp_value,
asset_name=asset_doc["name"],
asset_value=asset_value)
)
if invalid: if invalid:
def _on_repair(): def _on_repair():
@ -160,6 +159,11 @@ def validate_comp_prefs(comp=None):
attributes[comp_key_full] = value attributes[comp_key_full] = value
comp.SetPrefs(attributes) comp.SetPrefs(attributes)
if force_repair:
log.info("Applying default Comp preferences..")
_on_repair()
return
from . import menu from . import menu
from openpype.widgets import popup from openpype.widgets import popup
from openpype.style import load_stylesheet from openpype.style import load_stylesheet

View file

@ -16,6 +16,7 @@ from openpype.hosts.fusion.api.lib import (
from openpype.pipeline import legacy_io from openpype.pipeline import legacy_io
from openpype.resources import get_openpype_icon_filepath from openpype.resources import get_openpype_icon_filepath
from .pipeline import FusionEventHandler
from .pulse import FusionPulse from .pulse import FusionPulse
self = sys.modules[__name__] self = sys.modules[__name__]
@ -119,6 +120,10 @@ class OpenPypeMenu(QtWidgets.QWidget):
self._pulse = FusionPulse(parent=self) self._pulse = FusionPulse(parent=self)
self._pulse.start() self._pulse.start()
# Detect Fusion events as OpenPype events
self._event_handler = FusionEventHandler(parent=self)
self._event_handler.start()
def on_task_changed(self): def on_task_changed(self):
# Update current context label # Update current context label
label = legacy_io.Session["AVALON_ASSET"] label = legacy_io.Session["AVALON_ASSET"]

View file

@ -2,13 +2,16 @@
Basic avalon integration Basic avalon integration
""" """
import os import os
import sys
import logging import logging
import pyblish.api import pyblish.api
from Qt import QtCore
from openpype.lib import ( from openpype.lib import (
Logger, Logger,
register_event_callback register_event_callback,
emit_event
) )
from openpype.pipeline import ( from openpype.pipeline import (
register_loader_plugin_path, register_loader_plugin_path,
@ -39,12 +42,13 @@ CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
class CompLogHandler(logging.Handler): class FusionLogHandler(logging.Handler):
# Keep a reference to fusion's Print function (Remote Object)
_print = getattr(sys.modules["__main__"], "fusion").Print
def emit(self, record): def emit(self, record):
entry = self.format(record) entry = self.format(record)
comp = get_current_comp() self._print(entry)
if comp:
comp.Print(entry)
def install(): def install():
@ -67,7 +71,7 @@ def install():
# Attach default logging handler that prints to active comp # Attach default logging handler that prints to active comp
logger = logging.getLogger() logger = logging.getLogger()
formatter = logging.Formatter(fmt="%(message)s\n") formatter = logging.Formatter(fmt="%(message)s\n")
handler = CompLogHandler() handler = FusionLogHandler()
handler.setFormatter(formatter) handler.setFormatter(formatter)
logger.addHandler(handler) logger.addHandler(handler)
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
@ -84,10 +88,10 @@ def install():
"instanceToggled", on_pyblish_instance_toggled "instanceToggled", on_pyblish_instance_toggled
) )
# Fusion integration currently does not attach to direct callbacks of # Register events
# the application. So we use workfile callbacks to allow similar behavior register_event_callback("open", on_after_open)
# on save and open register_event_callback("save", on_save)
register_event_callback("workfile.open.after", on_after_open) register_event_callback("new", on_new)
def uninstall(): def uninstall():
@ -137,8 +141,18 @@ def on_pyblish_instance_toggled(instance, old_value, new_value):
tool.SetAttrs({"TOOLB_PassThrough": passthrough}) tool.SetAttrs({"TOOLB_PassThrough": passthrough})
def on_after_open(_event): def on_new(event):
comp = get_current_comp() comp = event["Rets"]["comp"]
validate_comp_prefs(comp, force_repair=True)
def on_save(event):
comp = event["sender"]
validate_comp_prefs(comp)
def on_after_open(event):
comp = event["sender"]
validate_comp_prefs(comp) validate_comp_prefs(comp)
if any_outdated_containers(): if any_outdated_containers():
@ -182,7 +196,7 @@ def ls():
""" """
comp = get_current_comp() comp = get_current_comp()
tools = comp.GetToolList(False, "Loader").values() tools = comp.GetToolList(False).values()
for tool in tools: for tool in tools:
container = parse_container(tool) container = parse_container(tool)
@ -254,3 +268,114 @@ def parse_container(tool):
return container return container
class FusionEventThread(QtCore.QThread):
"""QThread which will periodically ping Fusion app for any events.
The fusion.UIManager must be set up to be notified of events before they'll
be reported by this thread, for example:
fusion.UIManager.AddNotify("Comp_Save", None)
"""
on_event = QtCore.Signal(dict)
def run(self):
app = getattr(sys.modules["__main__"], "app", None)
if app is None:
# No Fusion app found
return
# As optimization store the GetEvent method directly because every
# getattr of UIManager.GetEvent tries to resolve the Remote Function
# through the PyRemoteObject
get_event = app.UIManager.GetEvent
delay = int(os.environ.get("OPENPYPE_FUSION_CALLBACK_INTERVAL", 1000))
while True:
if self.isInterruptionRequested():
return
# Process all events that have been queued up until now
while True:
event = get_event(False)
if not event:
break
self.on_event.emit(event)
# Wait some time before processing events again
# to not keep blocking the UI
self.msleep(delay)
class FusionEventHandler(QtCore.QObject):
"""Emits OpenPype events based on Fusion events captured in a QThread.
This will emit the following OpenPype events based on Fusion actions:
save: Comp_Save, Comp_SaveAs
open: Comp_Opened
new: Comp_New
To use this you can attach it to you Qt UI so it runs in the background.
E.g.
>>> handler = FusionEventHandler(parent=window)
>>> handler.start()
"""
ACTION_IDS = [
"Comp_Save",
"Comp_SaveAs",
"Comp_New",
"Comp_Opened"
]
def __init__(self, parent=None):
super(FusionEventHandler, self).__init__(parent=parent)
# Set up Fusion event callbacks
fusion = getattr(sys.modules["__main__"], "fusion", None)
ui = fusion.UIManager
# Add notifications for the ones we want to listen to
notifiers = []
for action_id in self.ACTION_IDS:
notifier = ui.AddNotify(action_id, None)
notifiers.append(notifier)
# TODO: Not entirely sure whether these must be kept to avoid
# garbage collection
self._notifiers = notifiers
self._event_thread = FusionEventThread(parent=self)
self._event_thread.on_event.connect(self._on_event)
def start(self):
self._event_thread.start()
def stop(self):
self._event_thread.stop()
def _on_event(self, event):
"""Handle Fusion events to emit OpenPype events"""
if not event:
return
what = event["what"]
# Comp Save
if what in {"Comp_Save", "Comp_SaveAs"}:
if not event["Rets"].get("success"):
# If the Save action is cancelled it will still emit an
# event but with "success": False so we ignore those cases
return
# Comp was saved
emit_event("save", data=event)
return
# Comp New
elif what in {"Comp_New"}:
emit_event("new", data=event)
# Comp Opened
elif what in {"Comp_Opened"}:
emit_event("open", data=event)

View file

@ -19,9 +19,12 @@ class PulseThread(QtCore.QThread):
while True: while True:
if self.isInterruptionRequested(): if self.isInterruptionRequested():
return return
try:
app.Test() # We don't need to call Test because PyRemoteObject of the app
except Exception: # will actually fail to even resolve the Test function if it has
# gone down. So we can actually already just check by confirming
# the method is still getting resolved. (Optimization)
if app.Test is None:
self.no_response.emit() self.no_response.emit()
self.msleep(interval) self.msleep(interval)

View file

@ -0,0 +1,70 @@
from openpype.pipeline import (
load,
get_representation_path,
)
from openpype.hosts.fusion.api import (
imprint_container,
get_current_comp,
comp_lock_and_undo_chunk
)
class FusionLoadAlembicMesh(load.LoaderPlugin):
"""Load Alembic mesh into Fusion"""
families = ["pointcache", "model"]
representations = ["abc"]
label = "Load alembic mesh"
order = -10
icon = "code-fork"
color = "orange"
tool_type = "SurfaceAlembicMesh"
def load(self, context, name, namespace, data):
# Fallback to asset name when namespace is None
if namespace is None:
namespace = context['asset']['name']
# Create the Loader with the filename path set
comp = get_current_comp()
with comp_lock_and_undo_chunk(comp, "Create tool"):
path = self.fname
args = (-32768, -32768)
tool = comp.AddTool(self.tool_type, *args)
tool["Filename"] = path
imprint_container(tool,
name=name,
namespace=namespace,
context=context,
loader=self.__class__.__name__)
def switch(self, container, representation):
self.update(container, representation)
def update(self, container, representation):
"""Update Alembic path"""
tool = container["_tool"]
assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
comp = tool.Comp()
path = get_representation_path(representation)
with comp_lock_and_undo_chunk(comp, "Update tool"):
tool["Filename"] = path
# Update the imprinted representation
tool.SetData("avalon.representation", str(representation["_id"]))
def remove(self, container):
tool = container["_tool"]
assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
comp = tool.Comp()
with comp_lock_and_undo_chunk(comp, "Remove tool"):
tool.Delete()

View file

@ -0,0 +1,71 @@
from openpype.pipeline import (
load,
get_representation_path,
)
from openpype.hosts.fusion.api import (
imprint_container,
get_current_comp,
comp_lock_and_undo_chunk
)
class FusionLoadFBXMesh(load.LoaderPlugin):
"""Load FBX mesh into Fusion"""
families = ["*"]
representations = ["fbx"]
label = "Load FBX mesh"
order = -10
icon = "code-fork"
color = "orange"
tool_type = "SurfaceFBXMesh"
def load(self, context, name, namespace, data):
# Fallback to asset name when namespace is None
if namespace is None:
namespace = context['asset']['name']
# Create the Loader with the filename path set
comp = get_current_comp()
with comp_lock_and_undo_chunk(comp, "Create tool"):
path = self.fname
args = (-32768, -32768)
tool = comp.AddTool(self.tool_type, *args)
tool["ImportFile"] = path
imprint_container(tool,
name=name,
namespace=namespace,
context=context,
loader=self.__class__.__name__)
def switch(self, container, representation):
self.update(container, representation)
def update(self, container, representation):
"""Update path"""
tool = container["_tool"]
assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
comp = tool.Comp()
path = get_representation_path(representation)
with comp_lock_and_undo_chunk(comp, "Update tool"):
tool["ImportFile"] = path
# Update the imprinted representation
tool.SetData("avalon.representation", str(representation["_id"]))
def remove(self, container):
tool = container["_tool"]
assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
comp = tool.Comp()
with comp_lock_and_undo_chunk(comp, "Remove tool"):
tool.Delete()

View file

@ -8,7 +8,7 @@ import hiero
from Qt import QtWidgets, QtCore from Qt import QtWidgets, QtCore
import qargparse import qargparse
import openpype.api as openpype from openpype.settings import get_current_project_settings
from openpype.lib import Logger from openpype.lib import Logger
from openpype.pipeline import LoaderPlugin, LegacyCreator from openpype.pipeline import LoaderPlugin, LegacyCreator
from openpype.pipeline.context_tools import get_current_project_asset from openpype.pipeline.context_tools import get_current_project_asset
@ -606,7 +606,7 @@ class Creator(LegacyCreator):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Creator, self).__init__(*args, **kwargs) super(Creator, self).__init__(*args, **kwargs)
import openpype.hosts.hiero.api as phiero import openpype.hosts.hiero.api as phiero
self.presets = openpype.get_current_project_settings()[ self.presets = get_current_project_settings()[
"hiero"]["create"].get(self.__class__.__name__, {}) "hiero"]["create"].get(self.__class__.__name__, {})
# adding basic current context resolve objects # adding basic current context resolve objects

View file

@ -35,6 +35,9 @@ class ValidateWorkfilePaths(pyblish.api.InstancePlugin):
def get_invalid(cls): def get_invalid(cls):
invalid = [] invalid = []
for param, _ in hou.fileReferences(): for param, _ in hou.fileReferences():
if param is None:
continue
# skip nodes we are not interested in # skip nodes we are not interested in
if param.node().type().name() not in cls.node_types: if param.node().type().name() not in cls.node_types:
continue continue

View file

@ -23,7 +23,7 @@ from openpype.client import (
get_last_versions, get_last_versions,
get_representation_by_name get_representation_by_name
) )
from openpype.api import get_anatomy_settings from openpype.settings import get_anatomy_settings
from openpype.pipeline import ( from openpype.pipeline import (
legacy_io, legacy_io,
discover_loader_plugins, discover_loader_plugins,

View file

@ -6,7 +6,7 @@ import six
import sys import sys
from openpype.lib import Logger from openpype.lib import Logger
from openpype.api import ( from openpype.settings import (
get_project_settings, get_project_settings,
get_current_project_settings get_current_project_settings
) )

View file

@ -9,7 +9,7 @@ import requests
from maya import cmds from maya import cmds
from maya.app.renderSetup.model import renderSetup from maya.app.renderSetup.model import renderSetup
from openpype.api import ( from openpype.settings import (
get_system_settings, get_system_settings,
get_project_settings, get_project_settings,
) )

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Creator for Unreal Static Meshes.""" """Creator for Unreal Static Meshes."""
from openpype.hosts.maya.api import plugin, lib from openpype.hosts.maya.api import plugin, lib
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import legacy_io from openpype.pipeline import legacy_io
from maya import cmds # noqa from maya import cmds # noqa

View file

@ -12,7 +12,7 @@ from openpype.hosts.maya.api import (
lib, lib,
plugin plugin
) )
from openpype.api import ( from openpype.settings import (
get_system_settings, get_system_settings,
get_project_settings get_project_settings
) )

View file

@ -1,7 +1,7 @@
import os import os
import clique import clique
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
load, load,
get_representation_path get_representation_path

View file

@ -4,7 +4,7 @@ from openpype.pipeline import (
load, load,
get_representation_path get_representation_path
) )
from openpype.api import get_project_settings from openpype.settings import get_project_settings
class GpuCacheLoader(load.LoaderPlugin): class GpuCacheLoader(load.LoaderPlugin):

View file

@ -5,7 +5,7 @@ import clique
import maya.cmds as cmds import maya.cmds as cmds
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
load, load,
get_representation_path get_representation_path

View file

@ -1,7 +1,7 @@
import os import os
from maya import cmds from maya import cmds
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import legacy_io from openpype.pipeline import legacy_io
from openpype.pipeline.create import ( from openpype.pipeline.create import (
legacy_create, legacy_create,

View file

@ -1,6 +1,6 @@
import os import os
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
load, load,
get_representation_path get_representation_path

View file

@ -1,6 +1,6 @@
import os import os
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
load, load,
get_representation_path get_representation_path

View file

@ -1,6 +1,6 @@
import os import os
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
load, load,
get_representation_path get_representation_path

View file

@ -10,7 +10,7 @@ import os
import maya.cmds as cmds import maya.cmds as cmds
from openpype.client import get_representation_by_name from openpype.client import get_representation_by_name
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
legacy_io, legacy_io,
load, load,

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import maya.cmds as cmds # noqa import maya.cmds as cmds # noqa
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
load, load,
get_representation_path get_representation_path

View file

@ -6,7 +6,7 @@ from collections import defaultdict
import clique import clique
from maya import cmds from maya import cmds
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
load, load,
get_representation_path get_representation_path
@ -250,7 +250,7 @@ class YetiCacheLoader(load.LoaderPlugin):
""" """
name = node_name.replace(":", "_") name = node_name.replace(":", "_")
pattern = r"^({name})(\.[0-4]+)?(\.fur)$".format(name=re.escape(name)) pattern = r"^({name})(\.[0-9]+)?(\.fur)$".format(name=re.escape(name))
files = [fname for fname in os.listdir(root) if re.match(pattern, files = [fname for fname in os.listdir(root) if re.match(pattern,
fname)] fname)]

View file

@ -1,7 +1,7 @@
import os import os
from collections import defaultdict from collections import defaultdict
from openpype.api import get_project_settings from openpype.settings import get_project_settings
import openpype.hosts.maya.api.plugin import openpype.hosts.maya.api.plugin
from openpype.hosts.maya.api import lib from openpype.hosts.maya.api import lib

View file

@ -136,8 +136,10 @@ class ExtractPlayblast(publish.Extractor):
self.log.debug("playblast path {}".format(path)) self.log.debug("playblast path {}".format(path))
collected_files = os.listdir(stagingdir) collected_files = os.listdir(stagingdir)
patterns = [clique.PATTERNS["frames"]]
collections, remainder = clique.assemble(collected_files, collections, remainder = clique.assemble(collected_files,
minimum_items=1) minimum_items=1,
patterns=patterns)
self.log.debug("filename {}".format(filename)) self.log.debug("filename {}".format(filename))
frame_collection = None frame_collection = None

View file

@ -11,7 +11,7 @@ import pyblish.api
from openpype.lib import requests_post from openpype.lib import requests_post
from openpype.hosts.maya.api import lib from openpype.hosts.maya.api import lib
from openpype.pipeline import legacy_io from openpype.pipeline import legacy_io
from openpype.api import get_system_settings from openpype.settings import get_system_settings
# mapping between Maya renderer names and Muster template ids # mapping between Maya renderer names and Muster template ids

View file

@ -1,5 +1,5 @@
import os import os
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import install_host from openpype.pipeline import install_host
from openpype.hosts.maya.api import MayaHost from openpype.hosts.maya.api import MayaHost
from maya import cmds from maya import cmds

View file

@ -7,9 +7,7 @@ import nuke
import pyblish.api import pyblish.api
import openpype import openpype
from openpype.api import ( from openpype.settings import get_current_project_settings
get_current_project_settings
)
from openpype.lib import register_event_callback, Logger from openpype.lib import register_event_callback, Logger
from openpype.pipeline import ( from openpype.pipeline import (
register_loader_plugin_path, register_loader_plugin_path,

View file

@ -6,7 +6,7 @@ from abc import abstractmethod
import nuke import nuke
from openpype.api import get_current_project_settings from openpype.settings import get_current_project_settings
from openpype.pipeline import ( from openpype.pipeline import (
LegacyCreator, LegacyCreator,
LoaderPlugin, LoaderPlugin,

View file

@ -504,7 +504,7 @@ class Creator(LegacyCreator):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Creator, self).__init__(*args, **kwargs) super(Creator, self).__init__(*args, **kwargs)
from openpype.api import get_current_project_settings from openpype.settings import get_current_project_settings
resolve_p_settings = get_current_project_settings().get("resolve") resolve_p_settings = get_current_project_settings().get("resolve")
self.presets = {} self.presets = {}
if resolve_p_settings: if resolve_p_settings:

View file

@ -1,6 +1,6 @@
import os import os
from openpype.lib import Logger from openpype.lib import Logger
from openpype.api import get_project_settings from openpype.settings import get_project_settings
log = Logger.get_logger(__name__) log = Logger.get_logger(__name__)

View file

@ -10,7 +10,7 @@ import pyblish.api
from openpype.client import get_project, get_asset_by_name from openpype.client import get_project, get_asset_by_name
from openpype.hosts import tvpaint from openpype.hosts import tvpaint
from openpype.api import get_current_project_settings from openpype.settings import get_current_project_settings
from openpype.lib import register_event_callback from openpype.lib import register_event_callback
from openpype.pipeline import ( from openpype.pipeline import (
legacy_io, legacy_io,

View file

@ -24,7 +24,7 @@ from openpype.pipeline import (
legacy_io, legacy_io,
) )
from openpype.pipeline.context_tools import get_current_project_asset from openpype.pipeline.context_tools import get_current_project_asset
from openpype.api import get_current_project_settings from openpype.settings import get_current_project_settings
from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import plugin
from openpype.hosts.unreal.api import pipeline as unreal_pipeline from openpype.hosts.unreal.api import pipeline as unreal_pipeline

View file

@ -500,6 +500,10 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline):
plugin_info["Renderer"] = renderer plugin_info["Renderer"] = renderer
# this is needed because renderman plugin in Deadline
# handles directory and file prefixes separately
plugin_info["OutputFilePath"] = job_info.OutputDirectory[0]
return job_info, plugin_info return job_info, plugin_info
def _get_vray_export_payload(self, data): def _get_vray_export_payload(self, data):

View file

@ -18,7 +18,7 @@ from openpype_modules.ftrack.lib import (
tool_definitions_from_app_manager tool_definitions_from_app_manager
) )
from openpype.api import get_system_settings from openpype.settings import get_system_settings
from openpype.lib import ApplicationManager from openpype.lib import ApplicationManager
""" """

View file

@ -1,7 +1,7 @@
import os import os
import ftrack_api import ftrack_api
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.lib import PostLaunchHook from openpype.lib import PostLaunchHook

View file

@ -43,7 +43,7 @@ import platform
import click import click
from openpype.modules import OpenPypeModule from openpype.modules import OpenPypeModule
from openpype.api import get_system_settings from openpype.settings import get_system_settings
class JobQueueModule(OpenPypeModule): class JobQueueModule(OpenPypeModule):

View file

@ -12,7 +12,7 @@ from openpype.client import (
get_assets, get_assets,
) )
from openpype.pipeline import AvalonMongoDB from openpype.pipeline import AvalonMongoDB
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.modules.kitsu.utils.credentials import validate_credentials from openpype.modules.kitsu.utils.credentials import validate_credentials

View file

@ -1,4 +1,4 @@
from openpype.api import get_system_settings, get_project_settings from openpype.settings import get_system_settings, get_project_settings
from openpype.modules.shotgrid.lib.const import MODULE_NAME from openpype.modules.shotgrid.lib.const import MODULE_NAME

View file

@ -1,5 +1,8 @@
from pyblish import api from pyblish import api
from openpype.api import get_current_project_settings, get_system_settings from openpype.settings import (
get_current_project_settings,
get_system_settings,
)
class CollectSettings(api.ContextPlugin): class CollectSettings(api.ContextPlugin):

View file

@ -4,8 +4,6 @@ import clique
import errno import errno
import shutil import shutil
from bson.objectid import ObjectId
from pymongo import InsertOne, ReplaceOne
import pyblish.api import pyblish.api
from openpype.client import ( from openpype.client import (
@ -14,10 +12,15 @@ from openpype.client import (
get_archived_representations, get_archived_representations,
get_representations, get_representations,
) )
from openpype.client.operations import (
OperationsSession,
new_hero_version_doc,
prepare_hero_version_update_data,
prepare_representation_update_data,
)
from openpype.lib import create_hard_link from openpype.lib import create_hard_link
from openpype.pipeline import ( from openpype.pipeline import (
schema, schema
legacy_io,
) )
from openpype.pipeline.publish import get_publish_template_name from openpype.pipeline.publish import get_publish_template_name
@ -187,35 +190,32 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
repre["name"].lower(): repre for repre in old_repres repre["name"].lower(): repre for repre in old_repres
} }
op_session = OperationsSession()
entity_id = None
if old_version: if old_version:
new_version_id = old_version["_id"] entity_id = old_version["_id"]
else: new_hero_version = new_hero_version_doc(
new_version_id = ObjectId() src_version_entity["_id"],
src_version_entity["parent"],
new_hero_version = { entity_id=entity_id
"_id": new_version_id, )
"version_id": src_version_entity["_id"],
"parent": src_version_entity["parent"],
"type": "hero_version",
"schema": "openpype:hero_version-1.0"
}
schema.validate(new_hero_version)
# Don't make changes in database until everything is O.K.
bulk_writes = []
if old_version: if old_version:
self.log.debug("Replacing old hero version.") self.log.debug("Replacing old hero version.")
bulk_writes.append( update_data = prepare_hero_version_update_data(
ReplaceOne( old_version, new_hero_version
{"_id": new_hero_version["_id"]}, )
new_hero_version op_session.update_entity(
) project_name,
new_hero_version["type"],
old_version["_id"],
update_data
) )
else: else:
self.log.debug("Creating first hero version.") self.log.debug("Creating first hero version.")
bulk_writes.append( op_session.create_entity(
InsertOne(new_hero_version) project_name, new_hero_version["type"], new_hero_version
) )
# Separate old representations into `to replace` and `to delete` # Separate old representations into `to replace` and `to delete`
@ -235,7 +235,7 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
archived_repres = list(get_archived_representations( archived_repres = list(get_archived_representations(
project_name, project_name,
# Check what is type of archived representation # Check what is type of archived representation
version_ids=[new_version_id] version_ids=[new_hero_version["_id"]]
)) ))
archived_repres_by_name = {} archived_repres_by_name = {}
for repre in archived_repres: for repre in archived_repres:
@ -382,12 +382,15 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
# Replace current representation # Replace current representation
if repre_name_low in old_repres_to_replace: if repre_name_low in old_repres_to_replace:
old_repre = old_repres_to_replace.pop(repre_name_low) old_repre = old_repres_to_replace.pop(repre_name_low)
repre["_id"] = old_repre["_id"] repre["_id"] = old_repre["_id"]
bulk_writes.append( update_data = prepare_representation_update_data(
ReplaceOne( old_repre, repre)
{"_id": old_repre["_id"]}, op_session.update_entity(
repre project_name,
) old_repre["type"],
old_repre["_id"],
update_data
) )
# Unarchive representation # Unarchive representation
@ -395,21 +398,21 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
archived_repre = archived_repres_by_name.pop( archived_repre = archived_repres_by_name.pop(
repre_name_low repre_name_low
) )
old_id = archived_repre["old_id"] repre["_id"] = archived_repre["old_id"]
repre["_id"] = old_id update_data = prepare_representation_update_data(
bulk_writes.append( archived_repre, repre)
ReplaceOne( op_session.update_entity(
{"old_id": old_id}, project_name,
repre old_repre["type"],
) archived_repre["_id"],
update_data
) )
# Create representation # Create representation
else: else:
repre["_id"] = ObjectId() repre.pop("_id", None)
bulk_writes.append( op_session.create_entity(project_name, "representation",
InsertOne(repre) repre)
)
self.path_checks = [] self.path_checks = []
@ -430,28 +433,22 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
archived_repre = archived_repres_by_name.pop( archived_repre = archived_repres_by_name.pop(
repre_name_low repre_name_low
) )
repre["old_id"] = repre["_id"]
repre["_id"] = archived_repre["_id"]
repre["type"] = archived_repre["type"]
bulk_writes.append(
ReplaceOne(
{"_id": archived_repre["_id"]},
repre
)
)
changes = {"old_id": repre["_id"],
"_id": archived_repre["_id"],
"type": archived_repre["type"]}
op_session.update_entity(project_name,
archived_repre["type"],
archived_repre["_id"],
changes)
else: else:
repre["old_id"] = repre["_id"] repre["old_id"] = repre.pop("_id")
repre["_id"] = ObjectId()
repre["type"] = "archived_representation" repre["type"] = "archived_representation"
bulk_writes.append( op_session.create_entity(project_name,
InsertOne(repre) "archived_representation",
) repre)
if bulk_writes: op_session.commit()
legacy_io.database[project_name].bulk_write(
bulk_writes
)
# Remove backuped previous hero # Remove backuped previous hero
if ( if (

View file

@ -6,7 +6,7 @@ from Qt import QtWidgets, QtCore
from openpype.client import get_asset_by_name, get_subsets from openpype.client import get_asset_by_name, get_subsets
from openpype import style from openpype import style
from openpype.api import get_current_project_settings from openpype.settings import get_current_project_settings
from openpype.tools.utils.lib import qt_app_context from openpype.tools.utils.lib import qt_app_context
from openpype.pipeline import legacy_io from openpype.pipeline import legacy_io
from openpype.pipeline.create import ( from openpype.pipeline.create import (

View file

@ -1256,7 +1256,11 @@ class RepresentationWidget(QtWidgets.QWidget):
repre_doc["parent"] repre_doc["parent"]
for repre_doc in repre_docs for repre_doc in repre_docs
] ]
version_docs = get_versions(project_name, version_ids=version_ids) version_docs = get_versions(
project_name,
version_ids=version_ids,
hero=True
)
version_docs_by_id = {} version_docs_by_id = {}
version_docs_by_subset_id = collections.defaultdict(list) version_docs_by_subset_id = collections.defaultdict(list)

View file

@ -22,7 +22,7 @@ import pyblish.version
from . import util from . import util
from .constants import InstanceStates from .constants import InstanceStates
from openpype.api import get_project_settings from openpype.settings import get_current_project_settings
class IterationBreak(Exception): class IterationBreak(Exception):
@ -204,7 +204,7 @@ class Controller(QtCore.QObject):
def presets_by_hosts(self): def presets_by_hosts(self):
# Get global filters as base # Get global filters as base
presets = get_project_settings(os.environ['AVALON_PROJECT']) or {} presets = get_current_project_settings()
if not presets: if not presets:
return {} return {}

View file

@ -34,7 +34,7 @@ import qtawesome
from six import text_type from six import text_type
from .constants import PluginStates, InstanceStates, GroupStates, Roles from .constants import PluginStates, InstanceStates, GroupStates, Roles
from openpype.api import get_system_settings from openpype.settings import get_system_settings
# ItemTypes # ItemTypes

View file

@ -2,6 +2,10 @@ from Qt import QtWidgets, QtGui
from openpype import style from openpype import style
from openpype.settings import (
SystemSettings,
ProjectSettings
)
from openpype.settings.lib import ( from openpype.settings.lib import (
get_local_settings, get_local_settings,
save_local_settings save_local_settings
@ -9,10 +13,6 @@ from openpype.settings.lib import (
from openpype.lib import Logger from openpype.lib import Logger
from openpype.tools.settings import CHILD_OFFSET from openpype.tools.settings import CHILD_OFFSET
from openpype.tools.utils import MessageOverlayObject from openpype.tools.utils import MessageOverlayObject
from openpype.api import (
SystemSettings,
ProjectSettings
)
from openpype.modules import ModulesManager from openpype.modules import ModulesManager
from .widgets import ( from .widgets import (

View file

@ -775,12 +775,26 @@ class PypeTrayStarter(QtCore.QObject):
def main(): def main():
log = Logger.get_logger(__name__) log = Logger.get_logger(__name__)
app = QtWidgets.QApplication.instance() app = QtWidgets.QApplication.instance()
high_dpi_scale_attr = None
if not app: if not app:
# 'AA_EnableHighDpiScaling' must be set before app instance creation
high_dpi_scale_attr = getattr(
QtCore.Qt, "AA_EnableHighDpiScaling", None
)
if high_dpi_scale_attr is not None:
QtWidgets.QApplication.setAttribute(high_dpi_scale_attr)
app = QtWidgets.QApplication([]) app = QtWidgets.QApplication([])
if high_dpi_scale_attr is None:
log.debug((
"Attribute 'AA_EnableHighDpiScaling' was not set."
" UI quality may be affected."
))
for attr_name in ( for attr_name in (
"AA_EnableHighDpiScaling", "AA_UseHighDpiPixmaps",
"AA_UseHighDpiPixmaps"
): ):
attr = getattr(QtCore.Qt, attr_name, None) attr = getattr(QtCore.Qt, attr_name, None)
if attr is None: if attr is None:

View file

@ -17,7 +17,7 @@ from openpype.style import (
) )
from openpype.resources import get_image_path from openpype.resources import get_image_path
from openpype.lib import filter_profiles, Logger from openpype.lib import filter_profiles, Logger
from openpype.api import get_project_settings from openpype.settings import get_project_settings
from openpype.pipeline import registered_host from openpype.pipeline import registered_host
log = Logger.get_logger(__name__) log = Logger.get_logger(__name__)

View file

@ -3,7 +3,7 @@ from Qt import QtWidgets, QtCore, QtGui
from openpype import style from openpype import style
from openpype.resources import get_resource from openpype.resources import get_resource
from openpype.api import get_system_settings from openpype.settings import get_system_settings
from openpype.settings.lib import ( from openpype.settings.lib import (
get_local_settings, get_local_settings,
save_local_settings save_local_settings