OP-2765 - merge develop

This commit is contained in:
Petr Kalis 2022-03-10 14:36:51 +01:00
commit 8360ab0c0d
114 changed files with 2249 additions and 414 deletions

View file

@ -43,7 +43,7 @@ jobs:
uses: heinrichreimer/github-changelog-generator-action@v2.2
with:
token: ${{ secrets.ADMIN_TOKEN }}
addSections: '{"documentation":{"prefix":"### 📖 Documentation","labels":["type: documentation"]},"tests":{"prefix":"### ✅ Testing","labels":["tests"]},"feature":{"prefix":"**🆕 New features**", "labels":["type: feature"]},"breaking":{"prefix":"**💥 Breaking**", "labels":["breaking"]},"enhancements":{"prefix":"**🚀 Enhancements**", "labels":["type: enhancement"]},"bugs":{"prefix":"**🐛 Bug fixes**", "labels":["type: bug"]},"deprecated":{"prefix":"**⚠️ Deprecations**", "labels":["depreciated"]}}'
addSections: '{"documentation":{"prefix":"### 📖 Documentation","labels":["type: documentation"]},"tests":{"prefix":"### ✅ Testing","labels":["tests"]},"feature":{"prefix":"**🆕 New features**", "labels":["type: feature"]},"breaking":{"prefix":"**💥 Breaking**", "labels":["breaking"]},"enhancements":{"prefix":"**🚀 Enhancements**", "labels":["type: enhancement"]},"bugs":{"prefix":"**🐛 Bug fixes**", "labels":["type: bug"]},"deprecated":{"prefix":"**⚠️ Deprecations**", "labels":["depreciated"]}, "refactor":{"prefix":"**🔀 Refactored code**", "labels":["refactor"]}}'
issues: false
issuesWoLabels: false
sinceTag: "3.0.0"

View file

@ -39,7 +39,7 @@ jobs:
uses: heinrichreimer/github-changelog-generator-action@v2.2
with:
token: ${{ secrets.ADMIN_TOKEN }}
addSections: '{"tests":{"prefix":"### ✅ Testing","labels":["tests"]},"feature":{"prefix":"**🆕 New features**", "labels":["type: feature"]},"breaking":{"prefix":"**💥 Breaking**", "labels":["breaking"]},"enhancements":{"prefix":"**🚀 Enhancements**", "labels":["type: enhancement"]},"bugs":{"prefix":"**🐛 Bug fixes**", "labels":["type: bug"]},"deprecated":{"prefix":"**⚠️ Deprecations**", "labels":["depreciated"]},"documentation":{"prefix":"### 📖 Documentation","labels":["type: documentation"]}}'
addSections: '{"documentation":{"prefix":"### 📖 Documentation","labels":["type: documentation"]},"tests":{"prefix":"### ✅ Testing","labels":["tests"]},"feature":{"prefix":"**🆕 New features**", "labels":["type: feature"]},"breaking":{"prefix":"**💥 Breaking**", "labels":["breaking"]},"enhancements":{"prefix":"**🚀 Enhancements**", "labels":["type: enhancement"]},"bugs":{"prefix":"**🐛 Bug fixes**", "labels":["type: bug"]},"deprecated":{"prefix":"**⚠️ Deprecations**", "labels":["depreciated"]}, "refactor":{"prefix":"**🔀 Refactored code**", "labels":["refactor"]}}'
issues: false
issuesWoLabels: false
sinceTag: "3.0.0"
@ -81,7 +81,7 @@ jobs:
uses: heinrichreimer/github-changelog-generator-action@v2.2
with:
token: ${{ secrets.ADMIN_TOKEN }}
addSections: '{"documentation":{"prefix":"### 📖 Documentation","labels":["type: documentation"]},"tests":{"prefix":"### ✅ Testing","labels":["tests"]},"feature":{"prefix":"**🆕 New features**", "labels":["type: feature"]},"breaking":{"prefix":"**💥 Breaking**", "labels":["breaking"]},"enhancements":{"prefix":"**🚀 Enhancements**", "labels":["type: enhancement"]},"bugs":{"prefix":"**🐛 Bug fixes**", "labels":["type: bug"]},"deprecated":{"prefix":"**⚠️ Deprecations**", "labels":["depreciated"]}}'
addSections: '{"documentation":{"prefix":"### 📖 Documentation","labels":["type: documentation"]},"tests":{"prefix":"### ✅ Testing","labels":["tests"]},"feature":{"prefix":"**🆕 New features**", "labels":["type: feature"]},"breaking":{"prefix":"**💥 Breaking**", "labels":["breaking"]},"enhancements":{"prefix":"**🚀 Enhancements**", "labels":["type: enhancement"]},"bugs":{"prefix":"**🐛 Bug fixes**", "labels":["type: bug"]},"deprecated":{"prefix":"**⚠️ Deprecations**", "labels":["depreciated"]}, "refactor":{"prefix":"**🔀 Refactored code**", "labels":["refactor"]}}'
issues: false
issuesWoLabels: false
sinceTag: ${{ steps.version.outputs.last_release }}

View file

@ -5,6 +5,7 @@ import platform
import functools
import logging
from openpype.pipeline import LegacyCreator
from .settings import get_project_settings
from .lib import (
Anatomy,
@ -58,10 +59,15 @@ def patched_discover(superclass):
"""
# run original discover and get plugins
plugins = _original_discover(superclass)
filtered_plugins = [
plugin
for plugin in plugins
if issubclass(plugin, superclass)
]
set_plugin_attributes_from_settings(plugins, superclass)
set_plugin_attributes_from_settings(filtered_plugins, superclass)
return plugins
return filtered_plugins
@import_wrapper
@ -113,7 +119,7 @@ def install():
pyblish.register_plugin_path(path)
avalon.register_plugin_path(avalon.Loader, path)
avalon.register_plugin_path(avalon.Creator, path)
avalon.register_plugin_path(LegacyCreator, path)
avalon.register_plugin_path(avalon.InventoryAction, path)
# apply monkey patched discover to original one

View file

@ -45,9 +45,6 @@ from .lib.avalon_context import (
from . import resources
from .plugin import (
PypeCreatorMixin,
Creator,
Extractor,
ValidatePipelineOrder,
@ -89,9 +86,6 @@ __all__ = [
# Resources
"resources",
# Pype creator mixin
"PypeCreatorMixin",
"Creator",
# plugin classes
"Extractor",
# ordering

View file

@ -14,6 +14,7 @@ import avalon.api
from avalon import io, schema
from avalon.pipeline import AVALON_CONTAINER_ID
from openpype.pipeline import LegacyCreator
from openpype.api import Logger
import openpype.hosts.blender
@ -46,7 +47,7 @@ def install():
pyblish.api.register_plugin_path(str(PUBLISH_PATH))
avalon.api.register_plugin_path(avalon.api.Loader, str(LOAD_PATH))
avalon.api.register_plugin_path(avalon.api.Creator, str(CREATE_PATH))
avalon.api.register_plugin_path(LegacyCreator, str(CREATE_PATH))
lib.append_user_scripts()
@ -67,7 +68,7 @@ def uninstall():
pyblish.api.deregister_plugin_path(str(PUBLISH_PATH))
avalon.api.deregister_plugin_path(avalon.api.Loader, str(LOAD_PATH))
avalon.api.deregister_plugin_path(avalon.api.Creator, str(CREATE_PATH))
avalon.api.deregister_plugin_path(LegacyCreator, str(CREATE_PATH))
if not IS_HEADLESS:
ops.unregister()

View file

@ -6,7 +6,7 @@ from typing import Dict, List, Optional
import bpy
import avalon.api
from openpype.api import PypeCreatorMixin
from openpype.pipeline import LegacyCreator
from .pipeline import AVALON_CONTAINERS
from .ops import (
MainThreadItem,
@ -129,7 +129,7 @@ def deselect_all():
bpy.context.view_layer.objects.active = active
class Creator(PypeCreatorMixin, avalon.api.Creator):
class Creator(LegacyCreator):
"""Base class for Creator plug-ins."""
defaults = ['Main']

View file

@ -8,6 +8,7 @@ import bpy
from avalon import api
from openpype import lib
from openpype.pipeline import legacy_create
from openpype.hosts.blender.api import plugin
from openpype.hosts.blender.api.pipeline import (
AVALON_CONTAINERS,
@ -159,7 +160,7 @@ class BlendLayoutLoader(plugin.AssetLoader):
raise ValueError("Creator plugin \"CreateAnimation\" was "
"not found.")
api.create(
legacy_create(
creator_plugin,
name=local_obj.name.split(':')[-1] + "_animation",
asset=asset,

View file

@ -8,7 +8,6 @@ from typing import Dict, Optional
import bpy
from avalon import api
from openpype import lib
from openpype.hosts.blender.api.pipeline import (
AVALON_INSTANCES,
AVALON_CONTAINERS,
@ -118,7 +117,7 @@ class JsonLayoutLoader(plugin.AssetLoader):
# raise ValueError("Creator plugin \"CreateCamera\" was "
# "not found.")
# api.create(
# legacy_create(
# creator_plugin,
# name="camera",
# # name=f"{unique_number}_{subset}_animation",

View file

@ -9,6 +9,7 @@ import bpy
from avalon import api
from avalon.blender import lib as avalon_lib
from openpype import lib
from openpype.pipeline import legacy_create
from openpype.hosts.blender.api import plugin
from openpype.hosts.blender.api.pipeline import (
AVALON_CONTAINERS,
@ -248,7 +249,7 @@ class BlendRigLoader(plugin.AssetLoader):
animation_asset = options.get('animation_asset')
api.create(
legacy_create(
creator_plugin,
name=namespace + "_animation",
# name=f"{unique_number}_{subset}_animation",

View file

@ -1,9 +1,9 @@
import os
import re
import json
import getpass
from avalon.vendor import requests
import re
import requests
import pyblish.api

View file

@ -7,6 +7,7 @@ from avalon import api as avalon
from avalon.pipeline import AVALON_CONTAINER_ID
from pyblish import api as pyblish
from openpype.api import Logger
from openpype.pipeline import LegacyCreator
from .lib import (
set_segment_data_marker,
set_publish_attribute,
@ -33,7 +34,7 @@ def install():
pyblish.register_host("flame")
pyblish.register_plugin_path(PUBLISH_PATH)
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
avalon.register_plugin_path(LegacyCreator, CREATE_PATH)
avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH)
log.info("OpenPype Flame plug-ins registred ...")
@ -48,7 +49,7 @@ def uninstall():
log.info("Deregistering Flame plug-ins..")
pyblish.deregister_plugin_path(PUBLISH_PATH)
avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
avalon.deregister_plugin_path(LegacyCreator, CREATE_PATH)
avalon.deregister_plugin_path(avalon.InventoryAction, INVENTORY_PATH)
# register callback for switching publishable

View file

@ -2,11 +2,12 @@ import os
import re
import shutil
import sys
from avalon.vendor import qargparse
from xml.etree import ElementTree as ET
import six
import qargparse
from Qt import QtWidgets, QtCore
import openpype.api as openpype
from openpype.pipeline import LegacyCreator
from openpype import style
import avalon.api as avalon
from . import (
@ -299,7 +300,7 @@ class Spacer(QtWidgets.QWidget):
self.setLayout(layout)
class Creator(openpype.Creator):
class Creator(LegacyCreator):
"""Creator class wrapper
"""
clip_color = constants.COLOR_MAP["purple"]

View file

@ -11,6 +11,7 @@ import avalon.api
from avalon.pipeline import AVALON_CONTAINER_ID
from openpype.api import Logger
from openpype.pipeline import LegacyCreator
import openpype.hosts.fusion
log = Logger().get_logger(__name__)
@ -63,7 +64,7 @@ def install():
log.info("Registering Fusion plug-ins..")
avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH)
avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH)
pyblish.api.register_callback(
@ -87,7 +88,7 @@ def uninstall():
log.info("Deregistering Fusion plug-ins..")
avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH)
avalon.api.deregister_plugin_path(
avalon.api.InventoryAction, INVENTORY_PATH
)

View file

@ -1,13 +1,13 @@
import os
import openpype.api
from openpype.pipeline import create
from openpype.hosts.fusion.api import (
get_current_comp,
comp_lock_and_undo_chunk
)
class CreateOpenEXRSaver(openpype.api.Creator):
class CreateOpenEXRSaver(create.LegacyCreator):
name = "openexrDefault"
label = "Create OpenEXR Saver"

View file

@ -1,5 +1,5 @@
from Qt import QtWidgets
from avalon.vendor import qtawesome
import qtawesome
from openpype.hosts.fusion.api import get_current_comp

View file

@ -6,7 +6,7 @@ from Qt import QtWidgets, QtCore
import avalon.api
from avalon import io
from avalon.vendor import qtawesome as qta
import qtawesome as qta
from openpype import style
from openpype.hosts.fusion import api

View file

@ -9,6 +9,7 @@ import avalon.api
from avalon.pipeline import AVALON_CONTAINER_ID
from openpype import lib
from openpype.pipeline import LegacyCreator
import openpype.hosts.harmony
import openpype.hosts.harmony.api as harmony
@ -179,7 +180,7 @@ def install():
pyblish.api.register_host("harmony")
pyblish.api.register_plugin_path(PUBLISH_PATH)
avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH)
log.info(PUBLISH_PATH)
# Register callbacks.
@ -193,7 +194,7 @@ def install():
def uninstall():
pyblish.api.deregister_plugin_path(PUBLISH_PATH)
avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH)
def on_pyblish_instance_toggled(instance, old_value, new_value):

View file

@ -1,9 +1,8 @@
import avalon.api
from openpype.api import PypeCreatorMixin
from openpype.pipeline import LegacyCreator
import openpype.hosts.harmony.api as harmony
class Creator(PypeCreatorMixin, avalon.api.Creator):
class Creator(LegacyCreator):
"""Creator plugin to create instances in Harmony.
By default a Composite node is created to support any number of nodes in

View file

@ -9,6 +9,7 @@ from avalon import api as avalon
from avalon import schema
from pyblish import api as pyblish
from openpype.api import Logger
from openpype.pipeline import LegacyCreator
from openpype.tools.utils import host_tools
from . import lib, menu, events
@ -45,7 +46,7 @@ def install():
pyblish.register_host("hiero")
pyblish.register_plugin_path(PUBLISH_PATH)
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
avalon.register_plugin_path(LegacyCreator, CREATE_PATH)
avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH)
# register callback for switching publishable
@ -67,7 +68,7 @@ def uninstall():
pyblish.deregister_host("hiero")
pyblish.deregister_plugin_path(PUBLISH_PATH)
avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
avalon.deregister_plugin_path(LegacyCreator, CREATE_PATH)
# register callback for switching publishable
pyblish.deregister_callback("instanceToggled", on_pyblish_instance_toggled)

View file

@ -1,12 +1,15 @@
import re
import os
import re
from copy import deepcopy
import hiero
from Qt import QtWidgets, QtCore
from avalon.vendor import qargparse
import qargparse
import avalon.api as avalon
import openpype.api as openpype
from openpype.pipeline import LegacyCreator
from . import lib
from copy import deepcopy
log = openpype.Logger().get_logger(__name__)
@ -589,7 +592,7 @@ class ClipLoader:
return track_item
class Creator(openpype.Creator):
class Creator(LegacyCreator):
"""Creator class wrapper
"""
clip_color = "Purple"

View file

@ -11,6 +11,7 @@ import avalon.api
from avalon.pipeline import AVALON_CONTAINER_ID
from avalon.lib import find_submodule
from openpype.pipeline import LegacyCreator
import openpype.hosts.houdini
from openpype.hosts.houdini.api import lib
@ -48,7 +49,7 @@ def install():
pyblish.api.register_plugin_path(PUBLISH_PATH)
avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH)
log.info("Installing callbacks ... ")
# avalon.on("init", on_init)

View file

@ -2,11 +2,12 @@
"""Houdini specific Avalon/Pyblish plugin definitions."""
import sys
import six
import avalon.api
from avalon.api import CreatorError
import hou
from openpype.api import PypeCreatorMixin
from openpype.pipeline import (
CreatorError,
LegacyCreator
)
from .lib import imprint
@ -14,7 +15,7 @@ class OpenPypeCreatorError(CreatorError):
pass
class Creator(PypeCreatorMixin, avalon.api.Creator):
class Creator(LegacyCreator):
"""Creator plugin to create instances in Houdini
To support the wide range of node types for render output (Alembic, VDB,

View file

@ -2,7 +2,6 @@ import os
import sys
import errno
import logging
import contextlib
from maya import utils, cmds, OpenMaya
import maya.api.OpenMaya as om
@ -17,6 +16,7 @@ import openpype.hosts.maya
from openpype.tools.utils import host_tools
from openpype.lib import any_outdated
from openpype.lib.path_tools import HostDirmap
from openpype.pipeline import LegacyCreator
from openpype.hosts.maya.lib import copy_workspace_mel
from . import menu, lib
@ -50,7 +50,7 @@ def install():
pyblish.api.register_host("maya")
avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH)
avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH)
log.info(PUBLISH_PATH)
@ -176,7 +176,7 @@ def uninstall():
pyblish.api.deregister_host("maya")
avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH)
avalon.api.deregister_plugin_path(
avalon.api.InventoryAction, INVENTORY_PATH
)

View file

@ -2,9 +2,10 @@ import os
from maya import cmds
import qargparse
from avalon import api
from avalon.vendor import qargparse
from openpype.api import PypeCreatorMixin
from openpype.pipeline import LegacyCreator
from .pipeline import containerise
from . import lib
@ -77,7 +78,7 @@ def get_reference_node_parents(ref):
return parents
class Creator(PypeCreatorMixin, api.Creator):
class Creator(LegacyCreator):
defaults = ['Main']
def process(self):

View file

@ -19,9 +19,9 @@ from openpype.api import (
get_project_settings,
get_asset)
from openpype.modules import ModulesManager
from openpype.pipeline import CreatorError
from avalon.api import Session
from avalon.api import CreatorError
class CreateRender(plugin.Creator):

View file

@ -19,10 +19,10 @@ from openpype.api import (
get_project_settings
)
from openpype.pipeline import CreatorError
from openpype.modules import ModulesManager
from avalon.api import Session
from avalon.api import CreatorError
class CreateVRayScene(plugin.Creator):

View file

@ -3,6 +3,7 @@ from maya import cmds
from avalon import api
from openpype.api import get_project_settings
from openpype.lib import get_creator_by_name
from openpype.pipeline import legacy_create
import openpype.hosts.maya.api.plugin
from openpype.hosts.maya.api.lib import maintained_selection
@ -151,7 +152,7 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader):
creator_plugin = get_creator_by_name(self.animation_creator_name)
with maintained_selection():
cmds.select([output, controls] + roots, noExpand=True)
api.create(
legacy_create(
creator_plugin,
name=namespace,
asset=asset,

View file

@ -174,7 +174,7 @@ class LoadVDBtoVRay(api.Loader):
fname = files[0]
else:
# Sequence
from avalon.vendor import clique
import clique
# todo: check support for negative frames as input
collections, remainder = clique.assemble(files)
assert len(collections) == 1, (

View file

@ -14,6 +14,7 @@ from openpype.api import (
BuildWorkfile,
get_current_project_settings
)
from openpype.pipeline import LegacyCreator
from openpype.tools.utils import host_tools
from .command import viewer_update_and_undo_stop
@ -98,7 +99,7 @@ def install():
log.info("Registering Nuke plug-ins..")
pyblish.api.register_plugin_path(PUBLISH_PATH)
avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH)
avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH)
# Register Avalon event for workfiles loading.
@ -124,7 +125,7 @@ def uninstall():
pyblish.deregister_host("nuke")
pyblish.api.deregister_plugin_path(PUBLISH_PATH)
avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH)
pyblish.api.deregister_callback(
"instanceToggled", on_pyblish_instance_toggled)

View file

@ -6,10 +6,8 @@ import nuke
import avalon.api
from openpype.api import (
get_current_project_settings,
PypeCreatorMixin
)
from openpype.api import get_current_project_settings
from openpype.pipeline import LegacyCreator
from .lib import (
Knobby,
check_subsetname_exists,
@ -20,7 +18,7 @@ from .lib import (
)
class OpenPypeCreator(PypeCreatorMixin, avalon.api.Creator):
class OpenPypeCreator(LegacyCreator):
"""Pype Nuke Creator class wrapper"""
node_color = "0xdfea5dff"

View file

@ -1,5 +1,5 @@
import nuke
from avalon.vendor import qargparse
import qargparse
from avalon import api, io
from openpype.hosts.nuke.api.lib import (

View file

@ -1,7 +1,6 @@
import re
import nuke
from avalon.vendor import qargparse
import qargparse
from avalon import api, io
from openpype.hosts.nuke.api.lib import (

View file

@ -16,7 +16,6 @@ from .pipeline import (
)
from .plugin import (
PhotoshopLoader,
Creator,
get_unique_layer_name
)
from .workio import (
@ -42,11 +41,11 @@ __all__ = [
"list_instances",
"remove_instance",
"install",
"uninstall",
"containerise",
# Plugin
"PhotoshopLoader",
"Creator",
"get_unique_layer_name",
# workfiles

View file

@ -1,5 +1,4 @@
import os
import sys
from Qt import QtWidgets
import pyblish.api
@ -7,6 +6,7 @@ import avalon.api
from avalon import pipeline, io
from openpype.api import Logger
from openpype.pipeline import LegacyCreator
import openpype.hosts.photoshop
from . import lib
@ -68,7 +68,7 @@ def install():
pyblish.api.register_plugin_path(PUBLISH_PATH)
avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH)
log.info(PUBLISH_PATH)
pyblish.api.register_callback(
@ -81,7 +81,7 @@ def install():
def uninstall():
pyblish.api.deregister_plugin_path(PUBLISH_PATH)
avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH)
def ls():

View file

@ -33,37 +33,3 @@ class PhotoshopLoader(avalon.api.Loader):
@staticmethod
def get_stub():
return stub()
class Creator(avalon.api.Creator):
"""Creator plugin to create instances in Photoshop
A LayerSet is created to support any number of layers in an instance. If
the selection is used, these layers will be added to the LayerSet.
"""
def process(self):
# Photoshop can have multiple LayerSets with the same name, which does
# not work with Avalon.
msg = "Instance with name \"{}\" already exists.".format(self.name)
stub = lib.stub() # only after Photoshop is up
for layer in stub.get_layers():
if self.name.lower() == layer.Name.lower():
msg = QtWidgets.QMessageBox()
msg.setIcon(QtWidgets.QMessageBox.Warning)
msg.setText(msg)
msg.exec_()
return False
# Store selection because adding a group will change selection.
with lib.maintained_selection():
# Add selection to group.
if (self.options or {}).get("useSelection"):
group = stub.group_selected_layers(self.name)
else:
group = stub.create_group(self.name)
stub.imprint(group, self.data)
return group

View file

@ -1,9 +1,9 @@
from Qt import QtWidgets
import openpype.api
from openpype.pipeline import create
from openpype.hosts.photoshop import api as photoshop
class CreateImage(openpype.api.Creator):
class CreateImage(create.LegacyCreator):
"""Image folder for publish."""
name = "imageDefault"

View file

@ -1,7 +1,7 @@
import os
import qargparse
from avalon.pipeline import get_representation_path_from_context
from avalon.vendor import qargparse
from openpype.hosts.photoshop import api as photoshop
from openpype.hosts.photoshop.api import get_unique_layer_name
@ -92,4 +92,3 @@ class ImageFromSequenceLoader(photoshop.PhotoshopLoader):
def remove(self, container):
"""No update possible, not containerized."""
pass

View file

@ -9,6 +9,7 @@ from avalon import schema
from avalon.pipeline import AVALON_CONTAINER_ID
from pyblish import api as pyblish
from openpype.api import Logger
from openpype.pipeline import LegacyCreator
from . import lib
from . import PLUGINS_DIR
from openpype.tools.utils import host_tools
@ -42,7 +43,7 @@ def install():
log.info("Registering DaVinci Resovle plug-ins..")
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
avalon.register_plugin_path(LegacyCreator, CREATE_PATH)
avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH)
# register callback for switching publishable
@ -67,7 +68,7 @@ def uninstall():
log.info("Deregistering DaVinci Resovle plug-ins..")
avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
avalon.deregister_plugin_path(LegacyCreator, CREATE_PATH)
avalon.deregister_plugin_path(avalon.InventoryAction, INVENTORY_PATH)
# register callback for switching publishable

View file

@ -1,12 +1,15 @@
import re
import uuid
import qargparse
from Qt import QtWidgets, QtCore
from avalon import api
import openpype.api as pype
from openpype.pipeline import LegacyCreator
from openpype.hosts import resolve
from avalon.vendor import qargparse
from . import lib
from Qt import QtWidgets, QtCore
class CreatorWidget(QtWidgets.QDialog):
@ -493,7 +496,7 @@ class TimelineItemLoader(api.Loader):
pass
class Creator(pype.PypeCreatorMixin, api.Creator):
class Creator(LegacyCreator):
"""Creator class wrapper
"""
marker_color = "Purple"

View file

@ -19,7 +19,7 @@ class CollectContextDataTestHost(
hosts = ["testhost"]
@classmethod
def get_instance_attr_defs(cls):
def get_attribute_defs(cls):
return [
attribute_definitions.BoolDef(
"test_bool",

View file

@ -20,7 +20,7 @@ class CollectInstanceOneTestHost(
hosts = ["testhost"]
@classmethod
def get_instance_attr_defs(cls):
def get_attribute_defs(cls):
return [
attribute_definitions.NumberDef(
"version",

View file

@ -14,6 +14,7 @@ from avalon.pipeline import AVALON_CONTAINER_ID
from openpype.hosts import tvpaint
from openpype.api import get_current_project_settings
from openpype.pipeline import LegacyCreator
from .lib import (
execute_george,
@ -76,7 +77,7 @@ def install():
pyblish.api.register_host("tvpaint")
pyblish.api.register_plugin_path(PUBLISH_PATH)
avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.register_plugin_path(LegacyCreator, CREATE_PATH)
registered_callbacks = (
pyblish.api.registered_callbacks().get("instanceToggled") or []
@ -98,7 +99,7 @@ def uninstall():
pyblish.api.deregister_host("tvpaint")
pyblish.api.deregister_plugin_path(PUBLISH_PATH)
avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.deregister_plugin_path(LegacyCreator, CREATE_PATH)
def containerise(

View file

@ -3,14 +3,14 @@ import uuid
import avalon.api
from openpype.api import PypeCreatorMixin
from openpype.pipeline import LegacyCreator
from openpype.hosts.tvpaint.api import (
pipeline,
lib
)
class Creator(PypeCreatorMixin, avalon.api.Creator):
class Creator(LegacyCreator):
def __init__(self, *args, **kwargs):
super(Creator, self).__init__(*args, **kwargs)
# Add unified identifier created with `uuid` module

View file

@ -1,5 +1,4 @@
from avalon.api import CreatorError
from openpype.pipeline import CreatorError
from openpype.lib import prepare_template_data
from openpype.hosts.tvpaint.api import (
plugin,

View file

@ -1,4 +1,4 @@
from avalon.api import CreatorError
from openpype.pipeline import CreatorError
from openpype.lib import prepare_template_data
from openpype.hosts.tvpaint.api import (
plugin,

View file

@ -1,4 +1,4 @@
from avalon.vendor import qargparse
import qargparse
from openpype.hosts.tvpaint.api import lib, plugin

View file

@ -1,6 +1,6 @@
import collections
import qargparse
from avalon.pipeline import get_representation_context
from avalon.vendor import qargparse
from openpype.hosts.tvpaint.api import lib, pipeline, plugin

View file

@ -7,6 +7,7 @@ import pyblish.api
from avalon.pipeline import AVALON_CONTAINER_ID
from avalon import api
from openpype.pipeline import LegacyCreator
from openpype.tools.utils import host_tools
import openpype.hosts.unreal
@ -44,7 +45,7 @@ def install():
logger.info("installing OpenPype for Unreal")
pyblish.api.register_plugin_path(str(PUBLISH_PATH))
api.register_plugin_path(api.Loader, str(LOAD_PATH))
api.register_plugin_path(api.Creator, str(CREATE_PATH))
api.register_plugin_path(LegacyCreator, str(CREATE_PATH))
_register_callbacks()
_register_events()
@ -53,7 +54,7 @@ def uninstall():
"""Uninstall Unreal configuration for Avalon."""
pyblish.api.deregister_plugin_path(str(PUBLISH_PATH))
api.deregister_plugin_path(api.Loader, str(LOAD_PATH))
api.deregister_plugin_path(api.Creator, str(CREATE_PATH))
api.deregister_plugin_path(LegacyCreator, str(CREATE_PATH))
def _register_callbacks():
@ -70,7 +71,7 @@ def _register_events():
pass
class Creator(api.Creator):
class Creator(LegacyCreator):
hosts = ["unreal"]
asset_types = []

View file

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
from abc import ABC
import openpype.api
from openpype.pipeline import LegacyCreator
import avalon.api
class Creator(openpype.api.Creator):
class Creator(LegacyCreator):
"""This serves as skeleton for future OpenPype specific functionality"""
defaults = ['Main']

View file

@ -5,6 +5,7 @@ from avalon import api as avalon
from avalon import io
from pyblish import api as pyblish
import openpype.hosts.webpublisher
from openpype.pipeline import LegacyCreator
log = logging.getLogger("openpype.hosts.webpublisher")
@ -25,7 +26,7 @@ def install():
pyblish.register_plugin_path(PUBLISH_PATH)
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
avalon.register_plugin_path(LegacyCreator, CREATE_PATH)
log.info(PUBLISH_PATH)
io.install()
@ -35,7 +36,7 @@ def install():
def uninstall():
pyblish.deregister_plugin_path(PUBLISH_PATH)
avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
avalon.deregister_plugin_path(LegacyCreator, CREATE_PATH)
# to have required methods for interface

View file

@ -159,6 +159,7 @@ from .plugin_tools import (
)
from .path_tools import (
create_hard_link,
version_up,
get_version_from_path,
get_last_version_from_path,
@ -291,6 +292,7 @@ __all__ = [
"get_unique_layer_name",
"get_background_layers",
"create_hard_link",
"version_up",
"get_version_from_path",
"get_last_version_from_path",

View file

@ -71,15 +71,14 @@ def path_from_representation(representation, anatomy):
def copy_file(src_path, dst_path):
"""Hardlink file if possible(to save space), copy if not"""
from avalon.vendor import filelink # safer importing
from openpype.lib import create_hard_link # safer importing
if os.path.exists(dst_path):
return
try:
filelink.create(
create_hard_link(
src_path,
dst_path,
filelink.HARDLINK
dst_path
)
except OSError:
shutil.copyfile(src_path, dst_path)

View file

@ -4,9 +4,9 @@ import abc
import json
import logging
import six
import platform
from openpype.settings import get_project_settings
from openpype.settings.lib import get_site_local_overrides
from .anatomy import Anatomy
from .profiles_filtering import filter_profiles
@ -14,6 +14,41 @@ from .profiles_filtering import filter_profiles
log = logging.getLogger(__name__)
def create_hard_link(src_path, dst_path):
"""Create hardlink of file.
Args:
src_path(str): Full path to a file which is used as source for
hardlink.
dst_path(str): Full path to a file where a link of source will be
added.
"""
# Use `os.link` if is available
# - should be for all platforms with newer python versions
if hasattr(os, "link"):
os.link(src_path, dst_path)
return
# Windows implementation of hardlinks
# - used in Python 2
if platform.system().lower() == "windows":
import ctypes
from ctypes.wintypes import BOOL
CreateHardLink = ctypes.windll.kernel32.CreateHardLinkW
CreateHardLink.argtypes = [
ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_void_p
]
CreateHardLink.restype = BOOL
res = CreateHardLink(dst_path, src_path, None)
if res == 0:
raise ctypes.WinError()
# Raises not implemented error if gets here
raise NotImplementedError(
"Implementation of hardlink for current environment is missing."
)
def _rreplace(s, a, b, n=1):
"""Replace a with b in string s from right side n times."""
return b.join(s.rsplit(a, n))

View file

@ -293,7 +293,7 @@ def set_plugin_attributes_from_settings(
plugin_type = None
if superclass.__name__.split(".")[-1] in ("Loader", "SubsetLoader"):
plugin_type = "load"
elif superclass.__name__.split(".")[-1] == "Creator":
elif superclass.__name__.split(".")[-1] in ("Creator", "LegacyCreator"):
plugin_type = "create"
if not host_name or not project_name or plugin_type is None:

View file

@ -61,6 +61,7 @@ class _ModuleClass(object):
def __init__(self, name):
# Call setattr on super class
super(_ModuleClass, self).__setattr__("name", name)
super(_ModuleClass, self).__setattr__("__name__", name)
# Where modules and interfaces are stored
super(_ModuleClass, self).__setattr__("__attributes__", dict())
@ -72,7 +73,7 @@ class _ModuleClass(object):
if attr_name not in self.__attributes__:
if attr_name in ("__path__", "__file__"):
return None
raise ImportError("No module named {}.{}".format(
raise AttributeError("'{}' has not attribute '{}'".format(
self.name, attr_name
))
return self.__attributes__[attr_name]

View file

@ -84,7 +84,9 @@ def inject_openpype_environment(deadlinePlugin):
with open(export_url) as fp:
contents = json.load(fp)
for key, value in contents.items():
deadlinePlugin.SetProcessEnvironmentVariable(key, value)
print("key:: {}".format(key))
if key != 'NUMBER_OF_PROCESSORS':
deadlinePlugin.SetProcessEnvironmentVariable(key, value)
print(">>> Removing temporary file")
os.remove(export_url)

View file

@ -1,5 +1,5 @@
from Qt import QtCore, QtWidgets
from avalon.vendor import qtawesome
import qtawesome
from .models import LogModel, LogsFilterProxy

View file

@ -4,9 +4,9 @@ from bson.objectid import ObjectId
from Qt import QtCore
from Qt.QtCore import Qt
import qtawesome
from openpype.tools.utils.delegates import pretty_timestamp
from avalon.vendor import qtawesome
from openpype.lib import PypeLogger
from openpype.api import get_local_site_id

View file

@ -5,6 +5,7 @@ from functools import partial
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCore import Qt
import qtawesome
from openpype.tools.settings import style
@ -12,7 +13,6 @@ from openpype.api import get_local_site_id
from openpype.lib import PypeLogger
from openpype.tools.utils.delegates import pretty_timestamp
from avalon.vendor import qtawesome
from .models import (
SyncRepresentationSummaryModel,

View file

@ -5,7 +5,10 @@ from .create import (
Creator,
AutoCreator,
CreatedInstance,
CreatorError
CreatorError,
LegacyCreator,
legacy_create,
)
from .publish import (
@ -25,6 +28,12 @@ __all__ = (
"CreatedInstance",
"CreatorError",
"CreatorError",
# Legacy creation
"LegacyCreator",
"legacy_create",
"PublishValidationError",
"PublishXmlValidationError",
"KnownPublishError",

View file

@ -14,6 +14,11 @@ from .context import (
CreateContext
)
from .legacy_create import (
LegacyCreator,
legacy_create,
)
__all__ = (
"SUBSET_NAME_ALLOWED_SYMBOLS",
@ -25,5 +30,8 @@ __all__ = (
"AutoCreator",
"CreatedInstance",
"CreateContext"
"CreateContext",
"LegacyCreator",
"legacy_create",
)

View file

@ -1005,12 +1005,14 @@ class CreateContext:
if not instances:
return
task_names_by_asset_name = collections.defaultdict(set)
task_names_by_asset_name = {}
for instance in instances:
task_name = instance.get("task")
asset_name = instance.get("asset")
if asset_name and task_name:
task_names_by_asset_name[asset_name].add(task_name)
if asset_name:
task_names_by_asset_name[asset_name] = set()
if task_name:
task_names_by_asset_name[asset_name].add(task_name)
asset_names = [
asset_name

View file

@ -0,0 +1,156 @@
"""Create workflow moved from avalon-core repository.
Renamed classes and functions
- 'Creator' -> 'LegacyCreator'
- 'create' -> 'legacy_create'
"""
import logging
import collections
from openpype.lib import get_subset_name
class LegacyCreator(object):
"""Determine how assets are created"""
label = None
family = None
defaults = None
maintain_selection = True
dynamic_subset_keys = []
log = logging.getLogger("LegacyCreator")
def __init__(self, name, asset, options=None, data=None):
self.name = name # For backwards compatibility
self.options = options
# Default data
self.data = collections.OrderedDict()
self.data["id"] = "pyblish.avalon.instance"
self.data["family"] = self.family
self.data["asset"] = asset
self.data["subset"] = name
self.data["active"] = True
self.data.update(data or {})
def process(self):
pass
@classmethod
def get_dynamic_data(
cls, variant, task_name, asset_id, project_name, host_name
):
"""Return dynamic data for current Creator plugin.
By default return keys from `dynamic_subset_keys` attribute as mapping
to keep formatted template unchanged.
```
dynamic_subset_keys = ["my_key"]
---
output = {
"my_key": "{my_key}"
}
```
Dynamic keys may override default Creator keys (family, task, asset,
...) but do it wisely if you need.
All of keys will be converted into 3 variants unchanged, capitalized
and all upper letters. Because of that are all keys lowered.
This method can be modified to prefill some values just keep in mind it
is class method.
Returns:
dict: Fill data for subset name template.
"""
dynamic_data = {}
for key in cls.dynamic_subset_keys:
key = key.lower()
dynamic_data[key] = "{" + key + "}"
return dynamic_data
@classmethod
def get_subset_name(
cls, variant, task_name, asset_id, project_name, host_name=None
):
"""Return subset name created with entered arguments.
Logic extracted from Creator tool. This method should give ability
to get subset name without the tool.
TODO: Maybe change `variant` variable.
By default is output concatenated family with user text.
Args:
variant (str): What is entered by user in creator tool.
task_name (str): Context's task name.
asset_id (ObjectId): Mongo ID of context's asset.
project_name (str): Context's project name.
host_name (str): Name of host.
Returns:
str: Formatted subset name with entered arguments. Should match
config's logic.
"""
dynamic_data = cls.get_dynamic_data(
variant, task_name, asset_id, project_name, host_name
)
return get_subset_name(
cls.family,
variant,
task_name,
asset_id,
project_name,
host_name,
dynamic_data=dynamic_data
)
def legacy_create(Creator, name, asset, options=None, data=None):
"""Create a new instance
Associate nodes with a subset and family. These nodes are later
validated, according to their `family`, and integrated into the
shared environment, relative their `subset`.
Data relative each family, along with default data, are imprinted
into the resulting objectSet. This data is later used by extractors
and finally asset browsers to help identify the origin of the asset.
Arguments:
Creator (Creator): Class of creator
name (str): Name of subset
asset (str): Name of asset
options (dict, optional): Additional options from GUI
data (dict, optional): Additional data from GUI
Raises:
NameError on `subset` already exists
KeyError on invalid dynamic property
RuntimeError on host error
Returns:
Name of instance
"""
from avalon.api import registered_host
host = registered_host()
plugin = Creator(name, asset, options, data)
if plugin.maintain_selection is True:
with host.maintained_selection():
print("Running %s with maintained selection" % plugin)
instance = plugin.process()
return instance
print("Running %s" % plugin)
instance = plugin.process()
return instance

View file

@ -3,79 +3,12 @@ import os
import pyblish.api
import avalon.api
from openpype.lib import get_subset_name
ValidatePipelineOrder = pyblish.api.ValidatorOrder + 0.05
ValidateContentsOrder = pyblish.api.ValidatorOrder + 0.1
ValidateSceneOrder = pyblish.api.ValidatorOrder + 0.2
ValidateMeshOrder = pyblish.api.ValidatorOrder + 0.3
class PypeCreatorMixin:
"""Helper to override avalon's default class methods.
Mixin class must be used as first in inheritance order to override methods.
"""
dynamic_subset_keys = []
@classmethod
def get_dynamic_data(
cls, variant, task_name, asset_id, project_name, host_name
):
"""Return dynamic data for current Creator plugin.
By default return keys from `dynamic_subset_keys` attribute as mapping
to keep formatted template unchanged.
```
dynamic_subset_keys = ["my_key"]
---
output = {
"my_key": "{my_key}"
}
```
Dynamic keys may override default Creator keys (family, task, asset,
...) but do it wisely if you need.
All of keys will be converted into 3 variants unchanged, capitalized
and all upper letters. Because of that are all keys lowered.
This method can be modified to prefill some values just keep in mind it
is class method.
Returns:
dict: Fill data for subset name template.
"""
dynamic_data = {}
for key in cls.dynamic_subset_keys:
key = key.lower()
dynamic_data[key] = "{" + key + "}"
return dynamic_data
@classmethod
def get_subset_name(
cls, variant, task_name, asset_id, project_name, host_name=None
):
dynamic_data = cls.get_dynamic_data(
variant, task_name, asset_id, project_name, host_name
)
return get_subset_name(
cls.family,
variant,
task_name,
asset_id,
project_name,
host_name,
dynamic_data=dynamic_data
)
class Creator(PypeCreatorMixin, avalon.api.Creator):
pass
class ContextPlugin(pyblish.api.ContextPlugin):
def process(cls, *args, **kwargs):
super(ContextPlugin, cls).process(cls, *args, **kwargs)

View file

@ -5,10 +5,10 @@ import uuid
import clique
from pymongo import UpdateOne
import ftrack_api
import qargparse
from Qt import QtWidgets, QtCore
from avalon import api, style
from avalon.vendor import qargparse
from avalon.api import AvalonMongoDB
import avalon.pipeline
from openpype.api import Anatomy

View file

@ -7,7 +7,7 @@ import shutil
from pymongo import InsertOne, ReplaceOne
import pyblish.api
from avalon import api, io, schema
from avalon.vendor import filelink
from openpype.lib import create_hard_link
class IntegrateHeroVersion(pyblish.api.InstancePlugin):
@ -518,7 +518,7 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
# First try hardlink and copy if paths are cross drive
try:
filelink.create(src_path, dst_path, filelink.HARDLINK)
create_hard_link(src_path, dst_path)
# Return when successful
return

View file

@ -13,12 +13,14 @@ from pymongo import DeleteOne, InsertOne
import pyblish.api
from avalon import io
from avalon.api import format_template_with_optional_keys
from avalon.vendor import filelink
import openpype.api
from datetime import datetime
# from pype.modules import ModulesManager
from openpype.lib.profiles_filtering import filter_profiles
from openpype.lib import prepare_template_data
from openpype.lib import (
prepare_template_data,
create_hard_link
)
# this is needed until speedcopy for linux is fixed
if sys.platform == "win32":
@ -196,11 +198,15 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
"short": task_code
}
else:
elif "task" in anatomy_data:
# Just set 'task_name' variable to context task
task_name = anatomy_data["task"]["name"]
task_type = anatomy_data["task"]["type"]
else:
task_name = None
task_type = None
# Fill family in anatomy data
anatomy_data["family"] = instance.data.get("family")
@ -737,7 +743,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
self.log.critical("An unexpected error occurred.")
six.reraise(*sys.exc_info())
filelink.create(src, dst, filelink.HARDLINK)
create_hard_link(src, dst)
def get_subset(self, asset, instance):
subset_name = instance.data["subset"]
@ -823,8 +829,12 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
# - is there a chance that task name is not filled in anatomy
# data?
# - should we use context task in that case?
task_name = instance.data["anatomyData"]["task"]["name"]
task_type = instance.data["anatomyData"]["task"]["type"]
anatomy_data = instance.data["anatomyData"]
task_name = None
task_type = None
if "task" in anatomy_data:
task_name = anatomy_data["task"]["name"]
task_type = anatomy_data["task"]["type"]
filtering_criteria = {
"families": instance.data["family"],
"hosts": instance.context.data["hostName"],

View file

@ -185,8 +185,8 @@
"linux": []
},
"renderSpace": "ACEScg",
"viewName": "ACES 1.0 SDR-video",
"displayName": "sRGB"
"displayName": "sRGB",
"viewName": "ACES 1.0 SDR-video"
},
"colorManagementPreference": {
"configFilePath": {

View file

@ -15,33 +15,6 @@
"deadline"
]
},
"ProcessSubmittedJobOnFarm": {
"enabled": true,
"deadline_department": "",
"deadline_pool": "",
"deadline_group": "",
"deadline_chunk_size": 1,
"deadline_priority": 50,
"publishing_script": "",
"skip_integration_repre_list": [],
"aov_filter": {
"maya": [
".+(?:\\.|_)([Bb]eauty)(?:\\.|_).*"
],
"nuke": [
".*"
],
"aftereffects": [
".*"
],
"celaction": [
".*"
],
"harmony": [
".*"
]
}
},
"MayaSubmitDeadline": {
"enabled": true,
"optional": false,
@ -95,6 +68,33 @@
"group": "",
"department": "",
"multiprocess": true
},
"ProcessSubmittedJobOnFarm": {
"enabled": true,
"deadline_department": "",
"deadline_pool": "",
"deadline_group": "",
"deadline_chunk_size": 1,
"deadline_priority": 50,
"publishing_script": "",
"skip_integration_repre_list": [],
"aov_filter": {
"maya": [
".+(?:\\.|_)([Bb]eauty)(?:\\.|_).*"
],
"nuke": [
".*"
],
"aftereffects": [
".*"
],
"celaction": [
".*"
],
"harmony": [
".*"
]
}
}
}
}

View file

@ -44,4 +44,4 @@
"create_first_version": false,
"custom_templates": []
}
}
}

View file

@ -1266,6 +1266,12 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
font-size: 15pt;
font-weight: 750;
}
#ChooseProjectFrame {
border-radius: 10px;
}
#ChooseProjectView {
background: transparent;
}
/* Globally used names */
#Separator {

View file

@ -1,8 +1,9 @@
import avalon.api as api
import openpype
from openpype.pipeline import LegacyCreator
class MyTestCreator(api.Creator):
class MyTestCreator(LegacyCreator):
my_test_property = "A"
@ -26,8 +27,8 @@ def test_avalon_plugin_presets(monkeypatch, printer):
openpype.install()
api.register_host(Test())
api.register_plugin(api.Creator, MyTestCreator)
plugins = api.discover(api.Creator)
api.register_plugin(LegacyCreator, MyTestCreator)
plugins = api.discover(LegacyCreator)
printer("Test if we got our test plugin")
assert MyTestCreator in plugins
for p in plugins:

View file

@ -2,6 +2,7 @@ import uuid
from Qt import QtGui, QtCore
from avalon import api
from openpype.pipeline import LegacyCreator
from . constants import (
FAMILY_ROLE,
@ -21,7 +22,7 @@ class CreatorsModel(QtGui.QStandardItemModel):
self._creators_by_id = {}
items = []
creators = api.discover(api.Creator)
creators = api.discover(LegacyCreator)
for creator in creators:
item_id = str(uuid.uuid4())
self._creators_by_id[item_id] = creator

View file

@ -3,9 +3,8 @@ import inspect
from Qt import QtWidgets, QtCore, QtGui
from avalon.vendor import qtawesome
import qtawesome
from openpype import style
from openpype.pipeline.create import SUBSET_NAME_ALLOWED_SYMBOLS
from openpype.tools.utils import ErrorMessageBox

View file

@ -9,7 +9,12 @@ from avalon import api, io
from openpype import style
from openpype.api import get_current_project_settings
from openpype.tools.utils.lib import qt_app_context
from openpype.pipeline.create import SUBSET_NAME_ALLOWED_SYMBOLS
from openpype.pipeline.create import (
SUBSET_NAME_ALLOWED_SYMBOLS,
legacy_create,
CreatorError,
LegacyCreator,
)
from .model import CreatorsModel
from .widgets import (
@ -422,7 +427,7 @@ class CreatorWindow(QtWidgets.QDialog):
error_info = None
try:
api.create(
legacy_create(
creator_plugin,
subset_name,
asset_name,
@ -430,7 +435,7 @@ class CreatorWindow(QtWidgets.QDialog):
data={"variant": variant}
)
except api.CreatorError as exc:
except CreatorError as exc:
self.echo("Creator error: {}".format(str(exc)))
error_info = (str(exc), None)
@ -486,7 +491,7 @@ def show(debug=False, parent=None):
if debug:
from avalon import mock
for creator in mock.creators:
api.register_plugin(api.Creator, creator)
api.register_plugin(LegacyCreator, creator)
import traceback
sys.excepthook = lambda typ, val, tb: traceback.print_last()

View file

@ -16,7 +16,7 @@ provides a bridge between the file-based project inventory and configuration.
import os
from Qt import QtGui
from avalon.vendor import qtawesome
import qtawesome
from openpype.api import resources
ICON_CACHE = {}

View file

@ -7,7 +7,7 @@ import time
import appdirs
from Qt import QtCore, QtGui
from avalon.vendor import qtawesome
import qtawesome
from avalon import api
from openpype.lib import JSONSettingRegistry
from openpype.lib.applications import (

View file

@ -2,7 +2,7 @@ import copy
import time
import collections
from Qt import QtWidgets, QtCore, QtGui
from avalon.vendor import qtawesome
import qtawesome
from openpype.tools.flickcharm import FlickCharm
from openpype.tools.utils.assets_widget import SingleSelectAssetsWidget

View file

@ -8,7 +8,7 @@ from avalon.api import AvalonMongoDB
from openpype import style
from openpype.api import resources
from avalon.vendor import qtawesome
import qtawesome
from .models import (
LauncherModel,
ProjectModel

View file

@ -1,7 +1,7 @@
import inspect
from Qt import QtGui
import qtawesome
from avalon.vendor import qtawesome
from openpype.tools.utils.widgets import (
OptionalAction,
OptionDialog

View file

@ -8,8 +8,8 @@ from avalon import (
schema
)
from Qt import QtCore, QtGui
import qtawesome
from avalon.vendor import qtawesome
from avalon.lib import HeroVersionType
from openpype.tools.utils.models import TreeModel, Item

View file

@ -1,8 +1,8 @@
from collections import defaultdict
from Qt import QtCore
import qtawesome
from avalon.vendor import qtawesome
from avalon.style import colors
from openpype.tools.utils import models

View file

@ -1,7 +1,7 @@
import os
from Qt import QtCore, QtGui
from Qt import QtGui
from avalon.vendor import qtawesome
import qtawesome
from openpype.tools.utils import paint_image_with_color

View file

@ -873,8 +873,6 @@ class PublisherController:
"""
for idx, plugin in enumerate(self.publish_plugins):
self._publish_progress = idx
# Add plugin to publish report
self._publish_report.add_plugin_iter(plugin, self._publish_context)
# Reset current plugin validations error
self._publish_current_plugin_validation_errors = None
@ -902,6 +900,9 @@ class PublisherController:
):
yield MainThreadItem(self.stop_publish)
# Add plugin to publish report
self._publish_report.add_plugin_iter(plugin, self._publish_context)
# Trigger callback that new plugin is going to be processed
self._trigger_callbacks(
self._publish_plugin_changed_callback_refs, plugin

View file

@ -8,12 +8,14 @@ try:
except Exception:
commonmark = None
from Qt import QtWidgets, QtCore, QtGui
from openpype.lib import TaskNotSetError
from openpype.pipeline.create import (
CreatorError,
SUBSET_NAME_ALLOWED_SYMBOLS
)
from openpype.tools.utils import ErrorMessageBox
from .widgets import IconValuePixmapLabel
from .assets_widget import CreateDialogAssetsWidget
from .tasks_widget import CreateDialogTasksWidget
@ -27,7 +29,7 @@ from ..constants import (
SEPARATORS = ("---separator---", "---")
class CreateErrorMessageBox(QtWidgets.QDialog):
class CreateErrorMessageBox(ErrorMessageBox):
def __init__(
self,
creator_label,
@ -35,24 +37,38 @@ class CreateErrorMessageBox(QtWidgets.QDialog):
asset_name,
exc_msg,
formatted_traceback,
parent=None
parent
):
super(CreateErrorMessageBox, self).__init__(parent)
self.setWindowTitle("Creation failed")
self.setFocusPolicy(QtCore.Qt.StrongFocus)
if not parent:
self.setWindowFlags(
self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint
)
self._creator_label = creator_label
self._subset_name = subset_name
self._asset_name = asset_name
self._exc_msg = exc_msg
self._formatted_traceback = formatted_traceback
super(CreateErrorMessageBox, self).__init__("Creation failed", parent)
body_layout = QtWidgets.QVBoxLayout(self)
main_label = (
def _create_top_widget(self, parent_widget):
label_widget = QtWidgets.QLabel(parent_widget)
label_widget.setText(
"<span style='font-size:18pt;'>Failed to create</span>"
)
main_label_widget = QtWidgets.QLabel(main_label, self)
body_layout.addWidget(main_label_widget)
return label_widget
def _get_report_data(self):
report_message = (
"{creator}: Failed to create Subset: \"{subset}\""
" in Asset: \"{asset}\""
"\n\nError: {message}"
).format(
creator=self._creator_label,
subset=self._subset_name,
asset=self._asset_name,
message=self._exc_msg,
)
if self._formatted_traceback:
report_message += "\n\n{}".format(self._formatted_traceback)
return [report_message]
def _create_content(self, content_layout):
item_name_template = (
"<span style='font-weight:bold;'>Creator:</span> {}<br>"
"<span style='font-weight:bold;'>Subset:</span> {}<br>"
@ -61,48 +77,29 @@ class CreateErrorMessageBox(QtWidgets.QDialog):
exc_msg_template = "<span style='font-weight:bold'>{}</span>"
line = self._create_line()
body_layout.addWidget(line)
content_layout.addWidget(line)
item_name = item_name_template.format(
creator_label, subset_name, asset_name
)
item_name_widget = QtWidgets.QLabel(
item_name.replace("\n", "<br>"), self
)
body_layout.addWidget(item_name_widget)
exc_msg = exc_msg_template.format(exc_msg.replace("\n", "<br>"))
message_label_widget = QtWidgets.QLabel(exc_msg, self)
body_layout.addWidget(message_label_widget)
if formatted_traceback:
tb_widget = QtWidgets.QLabel(
formatted_traceback.replace("\n", "<br>"), self
item_name_widget = QtWidgets.QLabel(self)
item_name_widget.setText(
item_name_template.format(
self._creator_label, self._subset_name, self._asset_name
)
tb_widget.setTextInteractionFlags(
QtCore.Qt.TextBrowserInteraction
)
body_layout.addWidget(tb_widget)
footer_widget = QtWidgets.QWidget(self)
footer_layout = QtWidgets.QHBoxLayout(footer_widget)
button_box = QtWidgets.QDialogButtonBox(QtCore.Qt.Vertical)
button_box.setStandardButtons(
QtWidgets.QDialogButtonBox.StandardButton.Ok
)
button_box.accepted.connect(self._on_accept)
footer_layout.addWidget(button_box, alignment=QtCore.Qt.AlignRight)
body_layout.addWidget(footer_widget)
content_layout.addWidget(item_name_widget)
def _on_accept(self):
self.close()
message_label_widget = QtWidgets.QLabel(self)
message_label_widget.setText(
exc_msg_template.format(self.convert_text_for_html(self._exc_msg))
)
content_layout.addWidget(message_label_widget)
def _create_line(self):
line = QtWidgets.QFrame(self)
line.setFixedHeight(2)
line.setFrameShape(QtWidgets.QFrame.HLine)
line.setFrameShadow(QtWidgets.QFrame.Sunken)
return line
if self._formatted_traceback:
line_widget = self._create_line()
tb_widget = self._create_traceback_widget(
self._formatted_traceback
)
content_layout.addWidget(line_widget)
content_layout.addWidget(tb_widget)
# TODO add creator identifier/label to details
@ -201,7 +198,7 @@ class CreateDialog(QtWidgets.QDialog):
self._prereq_available = False
self.message_dialog = None
self._message_dialog = None
name_pattern = "^[{}]*$".format(SUBSET_NAME_ALLOWED_SYMBOLS)
self._name_pattern = name_pattern
@ -566,10 +563,9 @@ class CreateDialog(QtWidgets.QDialog):
if variant_value is None:
variant_value = self.variant_input.text()
match = self._compiled_name_pattern.match(variant_value)
valid = bool(match)
self.create_btn.setEnabled(valid)
if not valid:
self.create_btn.setEnabled(True)
if not self._compiled_name_pattern.match(variant_value):
self.create_btn.setEnabled(False)
self._set_variant_state_property("invalid")
self.subset_name_input.setText("< Invalid variant >")
return
@ -579,9 +575,16 @@ class CreateDialog(QtWidgets.QDialog):
asset_doc = copy.deepcopy(self._asset_doc)
# Calculate subset name with Creator plugin
subset_name = self._selected_creator.get_subset_name(
variant_value, task_name, asset_doc, project_name
)
try:
subset_name = self._selected_creator.get_subset_name(
variant_value, task_name, asset_doc, project_name
)
except TaskNotSetError:
self.create_btn.setEnabled(False)
self._set_variant_state_property("invalid")
self.subset_name_input.setText("< Missing task >")
return
self.subset_name_input.setText(subset_name)
self._validate_subset_name(subset_name, variant_value)
@ -694,14 +697,18 @@ class CreateDialog(QtWidgets.QDialog):
"family": family
}
error_info = None
error_msg = None
formatted_traceback = None
try:
self.controller.create(
creator_identifier, subset_name, instance_data, pre_create_data
creator_identifier,
subset_name,
instance_data,
pre_create_data
)
except CreatorError as exc:
error_info = (str(exc), None)
error_msg = str(exc)
# Use bare except because some hosts raise their exceptions that
# do not inherit from python's `BaseException`
@ -710,12 +717,17 @@ class CreateDialog(QtWidgets.QDialog):
formatted_traceback = "".join(traceback.format_exception(
exc_type, exc_value, exc_traceback
))
error_info = (str(exc_value), formatted_traceback)
error_msg = str(exc_value)
if error_info:
if error_msg is not None:
box = CreateErrorMessageBox(
creator_label, subset_name, asset_name, *error_info
creator_label,
subset_name,
asset_name,
error_msg,
formatted_traceback,
parent=self
)
box.show()
# Store dialog so is not garbage collected before is shown
self.message_dialog = box
self._message_dialog = box

View file

@ -467,12 +467,22 @@ class InstanceListView(AbstractInstanceView):
else:
active = False
group_names = set()
for instance_id in selected_instance_ids:
widget = self._widgets_by_id.get(instance_id)
if widget is not None:
widget.set_active(active)
if widget is None:
continue
widget.set_active(active)
group_name = self._group_by_instance_id.get(instance_id)
if group_name is not None:
group_names.add(group_name)
for group_name in group_names:
self._update_group_checkstate(group_name)
def _update_group_checkstate(self, group_name):
"""Update checkstate of one group."""
widget = self._group_widgets.get(group_name)
if widget is None:
return

View file

@ -17,9 +17,10 @@ class TasksModel(QtGui.QStandardItemModel):
controller (PublisherController): Controller which handles creation and
publishing.
"""
def __init__(self, controller):
def __init__(self, controller, allow_empty_task=False):
super(TasksModel, self).__init__()
self._allow_empty_task = allow_empty_task
self._controller = controller
self._items_by_name = {}
self._asset_names = []
@ -70,8 +71,14 @@ class TasksModel(QtGui.QStandardItemModel):
task_name (str): Name of task which should be available in asset's
tasks.
"""
task_names = self._task_names_by_asset_name.get(asset_name)
if task_names and task_name in task_names:
if asset_name not in self._task_names_by_asset_name:
return False
if self._allow_empty_task and not task_name:
return True
task_names = self._task_names_by_asset_name[asset_name]
if task_name in task_names:
return True
return False
@ -92,6 +99,8 @@ class TasksModel(QtGui.QStandardItemModel):
new_task_names = self.get_intersection_of_tasks(
task_names_by_asset_name
)
if self._allow_empty_task:
new_task_names.add("")
old_task_names = set(self._items_by_name.keys())
if new_task_names == old_task_names:
return
@ -111,7 +120,9 @@ class TasksModel(QtGui.QStandardItemModel):
item.setData(task_name, TASK_NAME_ROLE)
self._items_by_name[task_name] = item
new_items.append(item)
root_item.appendRows(new_items)
if new_items:
root_item.appendRows(new_items)
def headerData(self, section, orientation, role=None):
if role is None:

View file

@ -4,9 +4,9 @@ import re
import copy
import collections
from Qt import QtWidgets, QtCore, QtGui
import qtawesome
from avalon.vendor import qtawesome
from openpype.lib import TaskNotSetError
from openpype.widgets.attribute_defs import create_widget_for_attr_def
from openpype.tools import resources
from openpype.tools.flickcharm import FlickCharm
@ -471,6 +471,28 @@ class AssetsField(BaseClickableFrame):
self.set_selected_items(self._origin_value)
class TasksComboboxProxy(QtCore.QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(TasksComboboxProxy, self).__init__(*args, **kwargs)
self._filter_empty = False
def set_filter_empty(self, filter_empty):
if self._filter_empty is filter_empty:
return
self._filter_empty = filter_empty
self.invalidate()
def filterAcceptsRow(self, source_row, parent_index):
if self._filter_empty:
model = self.sourceModel()
source_index = model.index(
source_row, self.filterKeyColumn(), parent_index
)
if not source_index.data(QtCore.Qt.DisplayRole):
return False
return True
class TasksCombobox(QtWidgets.QComboBox):
"""Combobox to show tasks for selected instances.
@ -490,13 +512,16 @@ class TasksCombobox(QtWidgets.QComboBox):
delegate = QtWidgets.QStyledItemDelegate()
self.setItemDelegate(delegate)
model = TasksModel(controller)
self.setModel(model)
model = TasksModel(controller, True)
proxy_model = TasksComboboxProxy()
proxy_model.setSourceModel(model)
self.setModel(proxy_model)
self.currentIndexChanged.connect(self._on_index_change)
self._delegate = delegate
self._model = model
self._proxy_model = proxy_model
self._origin_value = []
self._origin_selection = []
self._selected_items = []
@ -507,6 +532,14 @@ class TasksCombobox(QtWidgets.QComboBox):
self._text = None
def set_invalid_empty_task(self, invalid=True):
self._proxy_model.set_filter_empty(invalid)
if invalid:
self._set_is_valid(False)
self.set_text("< One or more subsets require Task selected >")
else:
self.set_text(None)
def set_multiselection_text(self, text):
"""Change text shown when multiple different tasks are in context."""
self._multiselection_text = text
@ -596,6 +629,8 @@ class TasksCombobox(QtWidgets.QComboBox):
self._ignore_index_change = True
self._model.set_asset_names(asset_names)
self._proxy_model.set_filter_empty(False)
self._proxy_model.sort(0)
self._ignore_index_change = False
@ -641,6 +676,9 @@ class TasksCombobox(QtWidgets.QComboBox):
asset_task_combinations (list): List of tuples. Each item in
the list contain asset name and task name.
"""
self._proxy_model.set_filter_empty(False)
self._proxy_model.sort(0)
if asset_task_combinations is None:
asset_task_combinations = []
@ -932,7 +970,7 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
family_value_widget.set_value()
subset_value_widget.set_value()
submit_btn = QtWidgets.QPushButton("Submit", self)
submit_btn = QtWidgets.QPushButton("Confirm", self)
cancel_btn = QtWidgets.QPushButton("Cancel", self)
submit_btn.setEnabled(False)
cancel_btn.setEnabled(False)
@ -998,7 +1036,33 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
project_name = self.controller.project_name
subset_names = set()
invalid_tasks = False
for instance in self._current_instances:
new_variant_value = instance.get("variant")
new_asset_name = instance.get("asset")
new_task_name = instance.get("task")
if variant_value is not None:
new_variant_value = variant_value
if asset_name is not None:
new_asset_name = asset_name
if task_name is not None:
new_task_name = task_name
asset_doc = asset_docs_by_name[new_asset_name]
try:
new_subset_name = instance.creator.get_subset_name(
new_variant_value, new_task_name, asset_doc, project_name
)
except TaskNotSetError:
invalid_tasks = True
instance.set_task_invalid(True)
subset_names.add(instance["subset"])
continue
subset_names.add(new_subset_name)
if variant_value is not None:
instance["variant"] = variant_value
@ -1007,25 +1071,18 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
instance.set_asset_invalid(False)
if task_name is not None:
instance["task"] = task_name
instance["task"] = task_name or None
instance.set_task_invalid(False)
new_variant_value = instance.get("variant")
new_asset_name = instance.get("asset")
new_task_name = instance.get("task")
asset_doc = asset_docs_by_name[new_asset_name]
new_subset_name = instance.creator.get_subset_name(
new_variant_value, new_task_name, asset_doc, project_name
)
subset_names.add(new_subset_name)
instance["subset"] = new_subset_name
if invalid_tasks:
self.task_value_widget.set_invalid_empty_task()
self.subset_value_widget.set_value(subset_names)
self._set_btns_enabled(False)
self._set_btns_visible(False)
self._set_btns_visible(invalid_tasks)
self.instance_context_changed.emit()
@ -1098,7 +1155,7 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
variants.add(instance.get("variant") or self.unknown_value)
families.add(instance.get("family") or self.unknown_value)
asset_name = instance.get("asset") or self.unknown_value
task_name = instance.get("task") or self.unknown_value
task_name = instance.get("task") or ""
asset_names.add(asset_name)
asset_task_combinations.append((asset_name, task_name))
subset_names.add(instance.get("subset") or self.unknown_value)

View file

@ -29,10 +29,9 @@ import pyblish
from . import settings, util
from .awesome import tags as awesome
import Qt
from Qt import QtCore, QtGui
import qtawesome
from six import text_type
from .vendor import qtawesome
from .constants import PluginStates, InstanceStates, GroupStates, Roles
from openpype.api import get_system_settings

View file

@ -4,9 +4,9 @@ import logging
from collections import defaultdict
from Qt import QtCore, QtGui
from avalon import api, io, style, schema
from avalon.vendor import qtawesome
import qtawesome
from avalon import api, io, style, schema
from avalon.lib import HeroVersionType
from openpype.tools.utils.models import TreeModel, Item

View file

@ -1,9 +1,9 @@
import collections
import logging
from Qt import QtWidgets, QtCore
import qtawesome
from avalon import io, api, pipeline
from avalon.vendor import qtawesome
from .widgets import (
ButtonWithMenu,

View file

@ -3,9 +3,9 @@ import logging
from functools import partial
from Qt import QtWidgets, QtCore
import qtawesome
from avalon import io, api, style
from avalon.vendor import qtawesome
from avalon.lib import HeroVersionType
from openpype.modules import ModulesManager

View file

@ -2,7 +2,7 @@ import os
import sys
from Qt import QtWidgets, QtCore
from avalon.vendor import qtawesome
import qtawesome
from avalon import io, api
from openpype import style

View file

@ -1,9 +1,9 @@
import os
import sys
import traceback
import contextlib
from enum import Enum
from Qt import QtWidgets, QtCore
import qtawesome
from openpype.lib import get_openpype_version
from openpype.tools.utils import set_style_property
@ -63,7 +63,6 @@ from .item_widgets import (
PathInputWidget
)
from .color_widget import ColorWidget
from avalon.vendor import qtawesome
class CategoryState(Enum):

View file

@ -2,7 +2,7 @@ import os
import copy
import uuid
from Qt import QtWidgets, QtCore, QtGui
from avalon.vendor import qtawesome
import qtawesome
from avalon.mongodb import (
AvalonMongoConnection,
AvalonMongoDB

View file

@ -1,8 +1,8 @@
import logging
import collections
from Qt import QtCore, QtGui
import qtawesome
from . import TreeModel, Node
from avalon.vendor import qtawesome
from avalon import style

View file

@ -1,6 +1,6 @@
from Qt import QtCore
import qtawesome
from . import Node, TreeModel
from avalon.vendor import qtawesome
from avalon import style

View file

@ -1,9 +1,9 @@
import contextlib
from Qt import QtWidgets, QtCore
import qtawesome
from openpype.tools.utils import PlaceholderLineEdit
from avalon.vendor import qtawesome
from avalon import style
from . import RecursiveSortFilterProxyModel, AssetModel

View file

@ -1,14 +1,11 @@
import os
import re
from Qt import QtWidgets, QtCore
from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole
from . import FamilyDescriptionWidget
from openpype.api import (
get_project_settings,
Creator
)
from openpype.api import get_project_settings
from openpype.pipeline import LegacyCreator
from openpype.lib import TaskNotSetError
from openpype.pipeline.create import SUBSET_NAME_ALLOWED_SYMBOLS
@ -390,7 +387,7 @@ class FamilyWidget(QtWidgets.QWidget):
sp_settings = settings.get('standalonepublisher', {})
for key, creator_data in sp_settings.get("create", {}).items():
creator = type(key, (Creator, ), creator_data)
creator = type(key, (LegacyCreator, ), creator_data)
label = creator.label or creator.family
item = QtWidgets.QListWidgetItem(label)

View file

@ -1,7 +1,7 @@
from Qt import QtWidgets, QtCore, QtGui
from . import FamilyRole, PluginRole
from avalon.vendor import qtawesome
import six
from Qt import QtWidgets, QtCore, QtGui
import qtawesome
from . import FamilyRole, PluginRole
class FamilyDescriptionWidget(QtWidgets.QWidget):

Some files were not shown because too many files have changed in this diff Show more