mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'develop' into enhancement/OP-8157_Use-AYON-settings
This commit is contained in:
commit
0a02c360ca
70 changed files with 606 additions and 1364 deletions
102
.github/pr-glob-labeler.yml
vendored
Normal file
102
.github/pr-glob-labeler.yml
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
# Add type: unittest label if any changes in tests folders
|
||||
'type: unittest':
|
||||
- '*/*tests*/**/*'
|
||||
|
||||
# any changes in documentation structure
|
||||
'type: documentation':
|
||||
- '*/**/*website*/**/*'
|
||||
- '*/**/*docs*/**/*'
|
||||
|
||||
# hosts triage
|
||||
'host: Nuke':
|
||||
- '*/**/*nuke*'
|
||||
- '*/**/*nuke*/**/*'
|
||||
|
||||
'host: Photoshop':
|
||||
- '*/**/*photoshop*'
|
||||
- '*/**/*photoshop*/**/*'
|
||||
|
||||
'host: Harmony':
|
||||
- '*/**/*harmony*'
|
||||
- '*/**/*harmony*/**/*'
|
||||
|
||||
'host: UE':
|
||||
- '*/**/*unreal*'
|
||||
- '*/**/*unreal*/**/*'
|
||||
|
||||
'host: Houdini':
|
||||
- '*/**/*houdini*'
|
||||
- '*/**/*houdini*/**/*'
|
||||
|
||||
'host: Maya':
|
||||
- '*/**/*maya*'
|
||||
- '*/**/*maya*/**/*'
|
||||
|
||||
'host: Resolve':
|
||||
- '*/**/*resolve*'
|
||||
- '*/**/*resolve*/**/*'
|
||||
|
||||
'host: Blender':
|
||||
- '*/**/*blender*'
|
||||
- '*/**/*blender*/**/*'
|
||||
|
||||
'host: Hiero':
|
||||
- '*/**/*hiero*'
|
||||
- '*/**/*hiero*/**/*'
|
||||
|
||||
'host: Fusion':
|
||||
- '*/**/*fusion*'
|
||||
- '*/**/*fusion*/**/*'
|
||||
|
||||
'host: Flame':
|
||||
- '*/**/*flame*'
|
||||
- '*/**/*flame*/**/*'
|
||||
|
||||
'host: TrayPublisher':
|
||||
- '*/**/*traypublisher*'
|
||||
- '*/**/*traypublisher*/**/*'
|
||||
|
||||
'host: 3dsmax':
|
||||
- '*/**/*max*'
|
||||
- '*/**/*max*/**/*'
|
||||
|
||||
'host: TV Paint':
|
||||
- '*/**/*tvpaint*'
|
||||
- '*/**/*tvpaint*/**/*'
|
||||
|
||||
'host: CelAction':
|
||||
- '*/**/*celaction*'
|
||||
- '*/**/*celaction*/**/*'
|
||||
|
||||
'host: After Effects':
|
||||
- '*/**/*aftereffects*'
|
||||
- '*/**/*aftereffects*/**/*'
|
||||
|
||||
'host: Substance Painter':
|
||||
- '*/**/*substancepainter*'
|
||||
- '*/**/*substancepainter*/**/*'
|
||||
|
||||
# modules triage
|
||||
'module: Deadline':
|
||||
- '*/**/*deadline*'
|
||||
- '*/**/*deadline*/**/*'
|
||||
|
||||
'module: RoyalRender':
|
||||
- '*/**/*royalrender*'
|
||||
- '*/**/*royalrender*/**/*'
|
||||
|
||||
'module: Sitesync':
|
||||
- '*/**/*sync_server*'
|
||||
- '*/**/*sync_server*/**/*'
|
||||
|
||||
'module: Ftrack':
|
||||
- '*/**/*ftrack*'
|
||||
- '*/**/*ftrack*/**/*'
|
||||
|
||||
'module: Shotgrid':
|
||||
- '*/**/*shotgrid*'
|
||||
- '*/**/*shotgrid*/**/*'
|
||||
|
||||
'module: Kitsu':
|
||||
- '*/**/*kitsu*'
|
||||
- '*/**/*kitsu*/**/*'
|
||||
|
|
@ -49,7 +49,6 @@ class HostBase(object):
|
|||
Todo:
|
||||
- move content of 'install_host' as method of this class
|
||||
- register host object
|
||||
- install legacy_io
|
||||
- install global plugin paths
|
||||
- store registered plugin paths to this object
|
||||
- handle current context (project, asset, task)
|
||||
|
|
@ -133,8 +132,6 @@ class HostBase(object):
|
|||
can be opened multiple workfiles at one moment and change of context
|
||||
can't be caught properly.
|
||||
|
||||
Default implementation returns values from 'legacy_io.Session'.
|
||||
|
||||
Returns:
|
||||
Dict[str, Union[str, None]]: Context with 3 keys 'project_name',
|
||||
'asset_name' and 'task_name'. All of them can be 'None'.
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@ from wsrpc_aiohttp import (
|
|||
|
||||
from qtpy import QtCore
|
||||
|
||||
from ayon_core.lib import Logger
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.pipeline import install_host, legacy_io
|
||||
from ayon_core.lib import Logger, is_in_tests
|
||||
from ayon_core.pipeline import install_host
|
||||
from ayon_core.addon import AddonsManager
|
||||
from ayon_core.tools.utils import host_tools, get_ayon_qt_app
|
||||
from ayon_core.tools.adobe_webserver.app import WebServerTool
|
||||
|
|
@ -298,13 +297,10 @@ class AfterEffectsRoute(WebSocketRoute):
|
|||
log.info("Setting context change")
|
||||
log.info("project {} asset {} ".format(project, asset))
|
||||
if project:
|
||||
legacy_io.Session["AVALON_PROJECT"] = project
|
||||
os.environ["AVALON_PROJECT"] = project
|
||||
if asset:
|
||||
legacy_io.Session["AVALON_ASSET"] = asset
|
||||
os.environ["AVALON_ASSET"] = asset
|
||||
if task:
|
||||
legacy_io.Session["AVALON_TASK"] = task
|
||||
os.environ["AVALON_TASK"] = task
|
||||
|
||||
async def read(self):
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ from ayon_core.host import (
|
|||
from ayon_core.client import get_asset_by_name
|
||||
from ayon_core.pipeline import (
|
||||
schema,
|
||||
legacy_io,
|
||||
get_current_project_name,
|
||||
get_current_asset_name,
|
||||
register_loader_plugin_path,
|
||||
|
|
@ -380,7 +379,7 @@ def _on_task_changed():
|
|||
# `directory` attribute, so it opens in that directory (does it?).
|
||||
# https://docs.blender.org/api/blender2.8/bpy.types.Operator.html#calling-a-file-selector
|
||||
# https://docs.blender.org/api/blender2.8/bpy.types.WindowManager.html#bpy.types.WindowManager.fileselect_add
|
||||
workdir = legacy_io.Session["AVALON_WORKDIR"]
|
||||
workdir = os.getenv("AVALON_WORKDIR")
|
||||
log.debug("New working directory: %s", workdir)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ from ayon_core.lib import (
|
|||
EnumDef,
|
||||
)
|
||||
from ayon_core.pipeline import (
|
||||
legacy_io,
|
||||
Creator,
|
||||
CreatedInstance
|
||||
)
|
||||
|
|
@ -136,7 +135,7 @@ class GenericCreateSaver(Creator):
|
|||
ext = data["creator_attributes"]["image_format"]
|
||||
|
||||
# Subset change detected
|
||||
workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"])
|
||||
workdir = os.path.normpath(os.getenv("AVALON_WORKDIR"))
|
||||
formatting_data.update({
|
||||
"workdir": workdir,
|
||||
"frame": "0" * frame_padding,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from qtpy import QtWidgets, QtCore, QtGui
|
|||
|
||||
from ayon_core import style
|
||||
from ayon_core.client import get_asset_by_name
|
||||
from ayon_core.pipeline import legacy_io, get_current_project_name
|
||||
from ayon_core.pipeline import get_current_project_name
|
||||
from ayon_core.tools.utils.assets_widget import SingleSelectAssetsWidget
|
||||
|
||||
from pxr import Sdf
|
||||
|
|
@ -27,7 +27,8 @@ class SelectAssetDialog(QtWidgets.QWidget):
|
|||
self.setWindowTitle("Pick Asset")
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Popup)
|
||||
|
||||
assets_widget = SingleSelectAssetsWidget(legacy_io, parent=self)
|
||||
assets_widget = SingleSelectAssetsWidget(self)
|
||||
assets_widget.set_project_name(get_current_project_name(), False)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.addWidget(assets_widget)
|
||||
|
|
|
|||
|
|
@ -3141,119 +3141,6 @@ def fix_incompatible_containers():
|
|||
"ReferenceLoader", type="string")
|
||||
|
||||
|
||||
def _null(*args):
|
||||
pass
|
||||
|
||||
|
||||
class shelf():
|
||||
'''A simple class to build shelves in maya. Since the build method is empty,
|
||||
it should be extended by the derived class to build the necessary shelf
|
||||
elements. By default it creates an empty shelf called "customShelf".'''
|
||||
|
||||
###########################################################################
|
||||
'''This is an example shelf.'''
|
||||
# class customShelf(_shelf):
|
||||
# def build(self):
|
||||
# self.addButon(label="button1")
|
||||
# self.addButon("button2")
|
||||
# self.addButon("popup")
|
||||
# p = cmds.popupMenu(b=1)
|
||||
# self.addMenuItem(p, "popupMenuItem1")
|
||||
# self.addMenuItem(p, "popupMenuItem2")
|
||||
# sub = self.addSubMenu(p, "subMenuLevel1")
|
||||
# self.addMenuItem(sub, "subMenuLevel1Item1")
|
||||
# sub2 = self.addSubMenu(sub, "subMenuLevel2")
|
||||
# self.addMenuItem(sub2, "subMenuLevel2Item1")
|
||||
# self.addMenuItem(sub2, "subMenuLevel2Item2")
|
||||
# self.addMenuItem(sub, "subMenuLevel1Item2")
|
||||
# self.addMenuItem(p, "popupMenuItem3")
|
||||
# self.addButon("button3")
|
||||
# customShelf()
|
||||
###########################################################################
|
||||
|
||||
def __init__(self, name="customShelf", iconPath="", preset={}):
|
||||
self.name = name
|
||||
|
||||
self.iconPath = iconPath
|
||||
|
||||
self.labelBackground = (0, 0, 0, 0)
|
||||
self.labelColour = (.9, .9, .9)
|
||||
|
||||
self.preset = preset
|
||||
|
||||
self._cleanOldShelf()
|
||||
cmds.setParent(self.name)
|
||||
self.build()
|
||||
|
||||
def build(self):
|
||||
'''This method should be overwritten in derived classes to actually
|
||||
build the shelf elements. Otherwise, nothing is added to the shelf.'''
|
||||
for item in self.preset['items']:
|
||||
if not item.get('command'):
|
||||
item['command'] = self._null
|
||||
if item['type'] == 'button':
|
||||
self.addButon(item['name'],
|
||||
command=item['command'],
|
||||
icon=item['icon'])
|
||||
if item['type'] == 'menuItem':
|
||||
self.addMenuItem(item['parent'],
|
||||
item['name'],
|
||||
command=item['command'],
|
||||
icon=item['icon'])
|
||||
if item['type'] == 'subMenu':
|
||||
self.addMenuItem(item['parent'],
|
||||
item['name'],
|
||||
command=item['command'],
|
||||
icon=item['icon'])
|
||||
|
||||
def addButon(self, label, icon="commandButton.png",
|
||||
command=_null, doubleCommand=_null):
|
||||
'''
|
||||
Adds a shelf button with the specified label, command,
|
||||
double click command and image.
|
||||
'''
|
||||
cmds.setParent(self.name)
|
||||
if icon:
|
||||
icon = os.path.join(self.iconPath, icon)
|
||||
print(icon)
|
||||
cmds.shelfButton(width=37, height=37, image=icon, label=label,
|
||||
command=command, dcc=doubleCommand,
|
||||
imageOverlayLabel=label, olb=self.labelBackground,
|
||||
olc=self.labelColour)
|
||||
|
||||
def addMenuItem(self, parent, label, command=_null, icon=""):
|
||||
'''
|
||||
Adds a shelf button with the specified label, command,
|
||||
double click command and image.
|
||||
'''
|
||||
if icon:
|
||||
icon = os.path.join(self.iconPath, icon)
|
||||
print(icon)
|
||||
return cmds.menuItem(p=parent, label=label, c=command, i="")
|
||||
|
||||
def addSubMenu(self, parent, label, icon=None):
|
||||
'''
|
||||
Adds a sub menu item with the specified label and icon to
|
||||
the specified parent popup menu.
|
||||
'''
|
||||
if icon:
|
||||
icon = os.path.join(self.iconPath, icon)
|
||||
print(icon)
|
||||
return cmds.menuItem(p=parent, label=label, i=icon, subMenu=1)
|
||||
|
||||
def _cleanOldShelf(self):
|
||||
'''
|
||||
Checks if the shelf exists and empties it if it does
|
||||
or creates it if it does not.
|
||||
'''
|
||||
if cmds.shelfLayout(self.name, ex=1):
|
||||
if cmds.shelfLayout(self.name, q=1, ca=1):
|
||||
for each in cmds.shelfLayout(self.name, q=1, ca=1):
|
||||
cmds.deleteUI(each)
|
||||
else:
|
||||
cmds.shelfLayout(self.name, p="ShelfLayout")
|
||||
|
||||
|
||||
def update_content_on_context_change():
|
||||
"""
|
||||
This will update scene content to match new asset on context change
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import maya.cmds as cmds
|
|||
|
||||
from ayon_core.pipeline import (
|
||||
get_current_asset_name,
|
||||
get_current_task_name
|
||||
get_current_task_name,
|
||||
registered_host
|
||||
)
|
||||
from ayon_core.pipeline.workfile import BuildWorkfile
|
||||
from ayon_core.tools.utils import host_tools
|
||||
|
|
@ -21,8 +22,10 @@ from .workfile_template_builder import (
|
|||
create_placeholder,
|
||||
update_placeholder,
|
||||
build_workfile_template,
|
||||
update_workfile_template,
|
||||
update_workfile_template
|
||||
)
|
||||
from ayon_core.tools.workfile_template_build import open_template_ui
|
||||
from .workfile_template_builder import MayaTemplateBuilder
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -167,16 +170,6 @@ def install(project_settings):
|
|||
tearOff=True,
|
||||
parent=MENU_NAME
|
||||
)
|
||||
cmds.menuItem(
|
||||
"Create Placeholder",
|
||||
parent=builder_menu,
|
||||
command=create_placeholder
|
||||
)
|
||||
cmds.menuItem(
|
||||
"Update Placeholder",
|
||||
parent=builder_menu,
|
||||
command=update_placeholder
|
||||
)
|
||||
cmds.menuItem(
|
||||
"Build Workfile from template",
|
||||
parent=builder_menu,
|
||||
|
|
@ -187,6 +180,27 @@ def install(project_settings):
|
|||
parent=builder_menu,
|
||||
command=update_workfile_template
|
||||
)
|
||||
cmds.menuItem(
|
||||
divider=True,
|
||||
parent=builder_menu
|
||||
)
|
||||
cmds.menuItem(
|
||||
"Open Template",
|
||||
parent=builder_menu,
|
||||
command=lambda *args: open_template_ui(
|
||||
MayaTemplateBuilder(registered_host()), get_main_window()
|
||||
),
|
||||
)
|
||||
cmds.menuItem(
|
||||
"Create Placeholder",
|
||||
parent=builder_menu,
|
||||
command=create_placeholder
|
||||
)
|
||||
cmds.menuItem(
|
||||
"Update Placeholder",
|
||||
parent=builder_menu,
|
||||
command=update_placeholder
|
||||
)
|
||||
|
||||
cmds.setParent(MENU_NAME, menu=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ from ayon_core.lib import (
|
|||
emit_event
|
||||
)
|
||||
from ayon_core.pipeline import (
|
||||
legacy_io,
|
||||
get_current_project_name,
|
||||
register_loader_plugin_path,
|
||||
register_inventory_action_path,
|
||||
|
|
@ -247,7 +246,7 @@ def _set_project():
|
|||
None
|
||||
|
||||
"""
|
||||
workdir = legacy_io.Session["AVALON_WORKDIR"]
|
||||
workdir = os.getenv("AVALON_WORKDIR")
|
||||
|
||||
try:
|
||||
os.makedirs(workdir)
|
||||
|
|
@ -629,7 +628,7 @@ def on_task_changed():
|
|||
# Run
|
||||
menu.update_menu_task_label()
|
||||
|
||||
workdir = legacy_io.Session["AVALON_WORKDIR"]
|
||||
workdir = os.getenv("AVALON_WORKDIR")
|
||||
if os.path.exists(workdir):
|
||||
log.info("Updating Maya workspace for task change to %s", workdir)
|
||||
_set_project()
|
||||
|
|
@ -678,7 +677,7 @@ def workfile_save_before_xgen(event):
|
|||
|
||||
import xgenm
|
||||
|
||||
current_work_dir = legacy_io.Session["AVALON_WORKDIR"].replace("\\", "/")
|
||||
current_work_dir = os.getenv("AVALON_WORKDIR").replace("\\", "/")
|
||||
expected_work_dir = event.data["workdir_path"].replace("\\", "/")
|
||||
if current_work_dir == expected_work_dir:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import maya.cmds as cmds
|
|||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
legacy_io,
|
||||
get_representation_path
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
|
|
@ -27,11 +26,6 @@ def is_sequence(files):
|
|||
return sequence
|
||||
|
||||
|
||||
def get_current_session_fps():
|
||||
session_fps = float(legacy_io.Session.get('AVALON_FPS', 25))
|
||||
return convert_to_maya_fps(session_fps)
|
||||
|
||||
|
||||
class ArnoldStandinLoader(load.LoaderPlugin):
|
||||
"""Load as Arnold standin"""
|
||||
|
||||
|
|
@ -101,7 +95,7 @@ class ArnoldStandinLoader(load.LoaderPlugin):
|
|||
sequence = is_sequence(os.listdir(os.path.dirname(repre_path)))
|
||||
cmds.setAttr(standin_shape + ".useFrameExtension", sequence)
|
||||
|
||||
fps = float(version["data"].get("fps"))or get_current_session_fps()
|
||||
fps = float(version["data"].get("fps")) or 25
|
||||
cmds.setAttr(standin_shape + ".abcFPS", fps)
|
||||
|
||||
nodes = [root, standin, standin_shape]
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Collect Vray Scene and prepare it for extraction and publishing."""
|
||||
import re
|
||||
|
||||
import maya.app.renderSetup.model.renderSetup as renderSetup
|
||||
from maya import cmds
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.lib import get_formatted_current_time
|
||||
from ayon_core.hosts.maya.api import lib
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import ayon_core.hosts.maya.api.action
|
|||
from ayon_core.client.mongo import OpenPypeMongoConnection
|
||||
from ayon_core.hosts.maya.api.shader_definition_editor import (
|
||||
DEFINITION_FILENAME)
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.pipeline.publish import (
|
||||
OptionalPyblishPluginMixin, PublishValidationError, ValidateContentsOrder)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import pyblish.api
|
|||
import ayon_core.hosts.maya.api.action
|
||||
from ayon_core.client import get_assets
|
||||
from ayon_core.hosts.maya.api import lib
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.pipeline.publish import (
|
||||
PublishValidationError, ValidatePipelineOrder)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import pyblish.api
|
|||
|
||||
import ayon_core.hosts.maya.api.action
|
||||
from ayon_core.client import get_subset_by_name
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.pipeline.publish import PublishValidationError
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from ayon_core.hosts.maya.api import lib
|
|||
from ayon_core.pipeline.publish import (
|
||||
RepairAction,
|
||||
ValidateContentsOrder,
|
||||
PublishValidationError
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -38,7 +39,8 @@ class ValidateRigJointsHidden(pyblish.api.InstancePlugin):
|
|||
invalid = self.get_invalid(instance)
|
||||
|
||||
if invalid:
|
||||
raise ValueError("Visible joints found: {0}".format(invalid))
|
||||
raise PublishValidationError(
|
||||
"Visible joints found: {0}".format(invalid))
|
||||
|
||||
@classmethod
|
||||
def repair(cls, instance):
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ import re
|
|||
import pyblish.api
|
||||
|
||||
import ayon_core.hosts.maya.api.action
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.pipeline.publish import (
|
||||
ValidateContentsOrder,
|
||||
OptionalPyblishPluginMixin,
|
||||
|
|
|
|||
|
|
@ -46,24 +46,5 @@ if bool(int(os.environ.get(key, "0"))):
|
|||
lowestPriority=True
|
||||
)
|
||||
|
||||
# Build a shelf.
|
||||
shelf_preset = settings['maya'].get('project_shelf')
|
||||
if shelf_preset:
|
||||
icon_path = os.path.join(
|
||||
os.environ['OPENPYPE_PROJECT_SCRIPTS'],
|
||||
project_name,
|
||||
"icons")
|
||||
icon_path = os.path.abspath(icon_path)
|
||||
|
||||
for i in shelf_preset['imports']:
|
||||
import_string = "from {} import {}".format(project_name, i)
|
||||
print(import_string)
|
||||
exec(import_string)
|
||||
|
||||
cmds.evalDeferred(
|
||||
"mlib.shelf(name=shelf_preset['name'], iconPath=icon_path,"
|
||||
" preset=shelf_preset)"
|
||||
)
|
||||
|
||||
|
||||
print("Finished OpenPype usersetup.")
|
||||
|
|
|
|||
|
|
@ -21,10 +21,12 @@ from ayon_core.pipeline import (
|
|||
AVALON_CONTAINER_ID,
|
||||
get_current_asset_name,
|
||||
get_current_task_name,
|
||||
registered_host,
|
||||
)
|
||||
from ayon_core.pipeline.workfile import BuildWorkfile
|
||||
from ayon_core.tools.utils import host_tools
|
||||
from ayon_core.hosts.nuke import NUKE_ROOT_DIR
|
||||
from ayon_core.tools.workfile_template_build import open_template_ui
|
||||
|
||||
from .command import viewer_update_and_undo_stop
|
||||
from .lib import (
|
||||
|
|
@ -55,6 +57,7 @@ from .workfile_template_builder import (
|
|||
build_workfile_template,
|
||||
create_placeholder,
|
||||
update_placeholder,
|
||||
NukeTemplateBuilder,
|
||||
)
|
||||
from .workio import (
|
||||
open_file,
|
||||
|
|
@ -313,7 +316,7 @@ def _install_menu():
|
|||
lambda: BuildWorkfile().process()
|
||||
)
|
||||
|
||||
menu_template = menu.addMenu("Template Builder") # creating template menu
|
||||
menu_template = menu.addMenu("Template Builder")
|
||||
menu_template.addCommand(
|
||||
"Build Workfile from template",
|
||||
lambda: build_workfile_template()
|
||||
|
|
@ -321,6 +324,12 @@ def _install_menu():
|
|||
|
||||
if not ASSIST:
|
||||
menu_template.addSeparator()
|
||||
menu_template.addCommand(
|
||||
"Open template",
|
||||
lambda: open_template_ui(
|
||||
NukeTemplateBuilder(registered_host()), get_main_window()
|
||||
)
|
||||
)
|
||||
menu_template.addCommand(
|
||||
"Create Place Holder",
|
||||
lambda: create_placeholder()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from ayon_core.pipeline.workfile.workfile_template_builder import (
|
|||
LoadPlaceholderItem,
|
||||
CreatePlaceholderItem,
|
||||
PlaceholderLoadMixin,
|
||||
PlaceholderCreateMixin
|
||||
PlaceholderCreateMixin,
|
||||
)
|
||||
from ayon_core.tools.workfile_template_build import (
|
||||
WorkfileBuildPlaceholderDialog,
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ import sys
|
|||
import contextlib
|
||||
import traceback
|
||||
|
||||
from ayon_core.lib import env_value_to_bool, Logger
|
||||
from ayon_core.lib import env_value_to_bool, Logger, is_in_tests
|
||||
from ayon_core.addon import AddonsManager
|
||||
from ayon_core.pipeline import install_host
|
||||
from ayon_core.tools.utils import host_tools
|
||||
from ayon_core.tools.utils import get_ayon_qt_app
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
|
||||
from .launch_logic import ProcessLauncher, stub
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,11 @@ import os
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from openpype_modules.webpublisher.lib import (
|
||||
get_batch_asset_task_info,
|
||||
parse_json
|
||||
)
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.lib import is_in_tests
|
||||
|
||||
|
||||
class CollectBatchData(pyblish.api.ContextPlugin):
|
||||
|
|
@ -71,8 +70,6 @@ class CollectBatchData(pyblish.api.ContextPlugin):
|
|||
|
||||
os.environ["AVALON_ASSET"] = asset_name
|
||||
os.environ["AVALON_TASK"] = task_name
|
||||
legacy_io.Session["AVALON_ASSET"] = asset_name
|
||||
legacy_io.Session["AVALON_TASK"] = task_name
|
||||
|
||||
context.data["asset"] = asset_name
|
||||
context.data["task"] = task_name
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ import re
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.lib import prepare_template_data
|
||||
from ayon_core.lib import prepare_template_data, is_in_tests
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
|
||||
|
||||
class CollectColorCodedInstances(pyblish.api.ContextPlugin):
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import pyblish.api
|
|||
|
||||
from ayon_core.pipeline import (
|
||||
register_creator_plugin_path,
|
||||
legacy_io,
|
||||
)
|
||||
from ayon_core.host import HostBase, IPublishHost
|
||||
|
||||
|
|
@ -24,7 +23,6 @@ class TrayPublisherHost(HostBase, IPublishHost):
|
|||
|
||||
def install(self):
|
||||
os.environ["AVALON_APP"] = self.name
|
||||
legacy_io.Session["AVALON_APP"] = self.name
|
||||
|
||||
pyblish.api.register_host("traypublisher")
|
||||
pyblish.api.register_plugin_path(PUBLISH_PATH)
|
||||
|
|
@ -43,8 +41,6 @@ class TrayPublisherHost(HostBase, IPublishHost):
|
|||
# TODO Deregister project specific plugins and register new project
|
||||
# plugins
|
||||
os.environ["AVALON_PROJECT"] = project_name
|
||||
legacy_io.Session["AVALON_PROJECT"] = project_name
|
||||
legacy_io.install()
|
||||
HostContext.set_project_name(project_name)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ from ayon_core.hosts.tvpaint import TVPAINT_ROOT_DIR
|
|||
from ayon_core.settings import get_current_project_settings
|
||||
from ayon_core.lib import register_event_callback
|
||||
from ayon_core.pipeline import (
|
||||
legacy_io,
|
||||
register_loader_plugin_path,
|
||||
register_creator_plugin_path,
|
||||
AVALON_CONTAINER_ID,
|
||||
|
|
@ -66,11 +65,10 @@ class TVPaintHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
|
|||
def install(self):
|
||||
"""Install TVPaint-specific functionality."""
|
||||
|
||||
log.info("OpenPype - Installing TVPaint integration")
|
||||
legacy_io.install()
|
||||
log.info("AYON - Installing TVPaint integration")
|
||||
|
||||
# Create workdir folder if does not exist yet
|
||||
workdir = legacy_io.Session["AVALON_WORKDIR"]
|
||||
workdir = os.getenv("AVALON_WORKDIR")
|
||||
if not os.path.exists(workdir):
|
||||
os.makedirs(workdir)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import tempfile
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.hosts.tvpaint.api.lib import (
|
||||
execute_george,
|
||||
execute_george_through_file,
|
||||
|
|
@ -90,7 +89,6 @@ class CollectWorkfileData(pyblish.api.ContextPlugin):
|
|||
("AVALON_TASK", "task_name")
|
||||
)
|
||||
for env_key, key in key_map:
|
||||
legacy_io.Session[env_key] = workfile_context[key]
|
||||
os.environ[env_key] = workfile_context[key]
|
||||
self.log.info("Context changed to: {}".format(workfile_context))
|
||||
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ from .ayon_info import (
|
|||
is_running_from_build,
|
||||
is_staging_enabled,
|
||||
is_dev_mode_enabled,
|
||||
is_in_tests,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -229,6 +230,8 @@ __all__ = [
|
|||
|
||||
"IniSettingRegistry",
|
||||
"JSONSettingRegistry",
|
||||
"AYONSecureRegistry",
|
||||
"AYONSettingsRegistry",
|
||||
"OpenPypeSecureRegistry",
|
||||
"OpenPypeSettingsRegistry",
|
||||
"get_local_site_id",
|
||||
|
|
@ -271,6 +274,7 @@ __all__ = [
|
|||
"terminal",
|
||||
|
||||
"get_datetime_data",
|
||||
"get_timestamp",
|
||||
"get_formatted_current_time",
|
||||
|
||||
"Logger",
|
||||
|
|
@ -278,6 +282,7 @@ __all__ = [
|
|||
"is_running_from_build",
|
||||
"is_staging_enabled",
|
||||
"is_dev_mode_enabled",
|
||||
"is_in_tests",
|
||||
|
||||
"requests_get",
|
||||
"requests_post"
|
||||
|
|
|
|||
|
|
@ -38,6 +38,16 @@ def is_staging_enabled():
|
|||
return os.getenv("AYON_USE_STAGING") == "1"
|
||||
|
||||
|
||||
def is_in_tests():
|
||||
"""Process is running in automatic tests mode.
|
||||
|
||||
Returns:
|
||||
bool: True if running in tests.
|
||||
|
||||
"""
|
||||
return os.environ.get("AYON_IN_TESTS") == "1"
|
||||
|
||||
|
||||
def is_dev_mode_enabled():
|
||||
"""Dev mode is enabled in AYON.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ from datetime import datetime
|
|||
from ayon_core.lib import (
|
||||
env_value_to_bool,
|
||||
collect_frames,
|
||||
is_in_tests,
|
||||
)
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from openpype_modules.deadline import abstract_submit_deadline
|
||||
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
|
||||
|
||||
@attr.s
|
||||
|
|
@ -84,13 +83,17 @@ class AfterEffectsSubmitDeadline(
|
|||
"AVALON_PROJECT",
|
||||
"AVALON_ASSET",
|
||||
"AVALON_TASK",
|
||||
"AVALON_WORKDIR",
|
||||
"AVALON_APP_NAME",
|
||||
"AYON_LOG_NO_COLORS",
|
||||
"IS_TEST"
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
for key in keys:
|
||||
value = environment.get(key)
|
||||
if value:
|
||||
|
|
|
|||
|
|
@ -10,11 +10,10 @@ from ayon_core.lib import (
|
|||
BoolDef,
|
||||
NumberDef,
|
||||
TextDef,
|
||||
is_in_tests,
|
||||
)
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.pipeline.publish import AYONPyblishPluginMixin
|
||||
from ayon_core.pipeline.farm.tools import iter_expected_files
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
|
||||
from openpype_modules.deadline import abstract_submit_deadline
|
||||
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||
|
|
@ -106,12 +105,16 @@ class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
|
|||
"AVALON_PROJECT",
|
||||
"AVALON_ASSET",
|
||||
"AVALON_TASK",
|
||||
"AVALON_WORKDIR",
|
||||
"AVALON_APP_NAME",
|
||||
"IS_TEST"
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
|
||||
for key in keys:
|
||||
value = environment.get(key)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import requests
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.pipeline.publish import (
|
||||
AYONPyblishPluginMixin
|
||||
)
|
||||
|
|
@ -224,14 +223,18 @@ class FusionSubmitDeadline(
|
|||
"AVALON_PROJECT",
|
||||
"AVALON_ASSET",
|
||||
"AVALON_TASK",
|
||||
"AVALON_WORKDIR",
|
||||
"AVALON_APP_NAME",
|
||||
"AYON_LOG_NO_COLORS",
|
||||
"IS_TEST",
|
||||
"AYON_BUNDLE_NAME",
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
|
||||
# to recognize render jobs
|
||||
environment["AYON_RENDER_JOB"] = "1"
|
||||
|
|
|
|||
|
|
@ -10,10 +10,9 @@ from datetime import datetime
|
|||
import attr
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from openpype_modules.deadline import abstract_submit_deadline
|
||||
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.lib import is_in_tests
|
||||
|
||||
|
||||
class _ZipFile(ZipFile):
|
||||
|
|
@ -277,13 +276,17 @@ class HarmonySubmitDeadline(
|
|||
"AVALON_PROJECT",
|
||||
"AVALON_ASSET",
|
||||
"AVALON_TASK",
|
||||
"AVALON_WORKDIR",
|
||||
"AVALON_APP_NAME",
|
||||
"AYON_LOG_NO_COLORS"
|
||||
"IS_TEST"
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
for key in keys:
|
||||
value = environment.get(key)
|
||||
if value:
|
||||
|
|
|
|||
|
|
@ -7,12 +7,11 @@ import pyblish.api
|
|||
from ayon_core.lib import (
|
||||
TextDef,
|
||||
NumberDef,
|
||||
is_in_tests,
|
||||
)
|
||||
from ayon_core.pipeline import (
|
||||
legacy_io,
|
||||
AYONPyblishPluginMixin
|
||||
)
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from openpype_modules.deadline import abstract_submit_deadline
|
||||
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||
|
||||
|
|
@ -102,12 +101,16 @@ class HoudiniCacheSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline
|
|||
"AVALON_PROJECT",
|
||||
"AVALON_ASSET",
|
||||
"AVALON_TASK",
|
||||
"AVALON_WORKDIR",
|
||||
"AVALON_APP_NAME",
|
||||
"AYON_LOG_NO_COLORS",
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
|
||||
for key in keys:
|
||||
value = environment.get(key)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ from datetime import datetime
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io, AYONPyblishPluginMixin
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.pipeline import AYONPyblishPluginMixin
|
||||
from openpype_modules.deadline import abstract_submit_deadline
|
||||
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||
from ayon_core.lib import (
|
||||
is_in_tests,
|
||||
BoolDef,
|
||||
NumberDef
|
||||
)
|
||||
|
|
@ -207,12 +207,16 @@ class HoudiniSubmitDeadline(
|
|||
"AVALON_PROJECT",
|
||||
"AVALON_ASSET",
|
||||
"AVALON_TASK",
|
||||
"AVALON_WORKDIR",
|
||||
"AVALON_APP_NAME",
|
||||
"AYON_LOG_NO_COLORS",
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
|
||||
for key in keys:
|
||||
value = environment.get(key)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ from ayon_core.lib import (
|
|||
NumberDef,
|
||||
)
|
||||
from ayon_core.pipeline import (
|
||||
legacy_io,
|
||||
AYONPyblishPluginMixin
|
||||
)
|
||||
from ayon_core.pipeline.publish.lib import (
|
||||
|
|
@ -110,12 +109,16 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
|
|||
"AVALON_PROJECT",
|
||||
"AVALON_ASSET",
|
||||
"AVALON_TASK",
|
||||
"AVALON_WORKDIR",
|
||||
"AVALON_APP_NAME",
|
||||
"IS_TEST"
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
|
||||
for key in keys:
|
||||
value = environment.get(key)
|
||||
|
|
|
|||
|
|
@ -30,21 +30,20 @@ from collections import OrderedDict
|
|||
import attr
|
||||
|
||||
from ayon_core.pipeline import (
|
||||
legacy_io,
|
||||
AYONPyblishPluginMixin
|
||||
)
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
NumberDef,
|
||||
TextDef,
|
||||
EnumDef
|
||||
EnumDef,
|
||||
is_in_tests,
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib_rendersettings import RenderSettings
|
||||
from ayon_core.hosts.maya.api.lib import get_attr_in_layer
|
||||
|
||||
from openpype_modules.deadline import abstract_submit_deadline
|
||||
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.pipeline.farm.tools import iter_expected_files
|
||||
|
||||
|
||||
|
|
@ -211,12 +210,16 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
|
|||
"AVALON_PROJECT",
|
||||
"AVALON_ASSET",
|
||||
"AVALON_TASK",
|
||||
"AVALON_WORKDIR",
|
||||
"AVALON_APP_NAME",
|
||||
"IS_TEST"
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
|
||||
for key in keys:
|
||||
value = environment.get(key)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import os
|
|||
import attr
|
||||
from datetime import datetime
|
||||
|
||||
from ayon_core.pipeline import legacy_io, PublishXmlValidationError
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.pipeline import PublishXmlValidationError
|
||||
from ayon_core.lib import is_in_tests
|
||||
from openpype_modules.deadline import abstract_submit_deadline
|
||||
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||
|
||||
|
|
@ -98,10 +98,12 @@ class MayaSubmitRemotePublishDeadline(
|
|||
"FTRACK_SERVER"
|
||||
]
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
|
||||
# TODO replace legacy_io with context.data
|
||||
environment["AVALON_PROJECT"] = project_name
|
||||
environment["AVALON_ASSET"] = instance.context.data["asset"]
|
||||
environment["AVALON_TASK"] = instance.context.data["task"]
|
||||
|
|
|
|||
|
|
@ -7,12 +7,11 @@ from datetime import datetime
|
|||
import requests
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.pipeline.publish import (
|
||||
AYONPyblishPluginMixin
|
||||
)
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.lib import (
|
||||
is_in_tests,
|
||||
BoolDef,
|
||||
NumberDef
|
||||
)
|
||||
|
|
@ -393,8 +392,11 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin,
|
|||
if self.env_allowed_keys:
|
||||
keys += self.env_allowed_keys
|
||||
|
||||
environment = dict({key: os.environ[key] for key in keys
|
||||
if key in os.environ}, **legacy_io.Session)
|
||||
environment = {
|
||||
key: os.environ[key]
|
||||
for key in keys
|
||||
if key in os.environ
|
||||
}
|
||||
|
||||
# to recognize render jobs
|
||||
environment["AYON_RENDER_JOB"] = "1"
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@ import pyblish.api
|
|||
from ayon_core.client import (
|
||||
get_last_version_by_subset_name,
|
||||
)
|
||||
from ayon_core.pipeline import publish, legacy_io
|
||||
from ayon_core.lib import EnumDef, is_running_from_build
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_core.lib import EnumDef, is_in_tests
|
||||
from ayon_core.pipeline.version_start import get_versioning_start
|
||||
|
||||
from ayon_core.pipeline.farm.pyblish_functions import (
|
||||
|
|
@ -370,7 +369,6 @@ class ProcessSubmittedCacheJobOnFarm(pyblish.api.InstancePlugin,
|
|||
"intent": instance.context.data.get("intent"),
|
||||
"comment": instance.context.data.get("comment"),
|
||||
"job": render_job or None,
|
||||
"session": legacy_io.Session.copy(),
|
||||
"instances": instances
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ import pyblish.api
|
|||
from ayon_core.client import (
|
||||
get_last_version_by_subset_name,
|
||||
)
|
||||
from ayon_core.pipeline import publish, legacy_io
|
||||
from ayon_core.lib import EnumDef, is_running_from_build
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_core.lib import EnumDef, is_in_tests
|
||||
from ayon_core.pipeline.version_start import get_versioning_start
|
||||
|
||||
from ayon_core.pipeline.farm.pyblish_functions import (
|
||||
|
|
@ -631,7 +630,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin,
|
|||
"intent": instance.context.data.get("intent"),
|
||||
"comment": instance.context.data.get("comment"),
|
||||
"job": render_job or None,
|
||||
"session": legacy_io.Session.copy(),
|
||||
"instances": instances
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,12 @@ from datetime import datetime
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.lib import BoolDef, NumberDef, is_running_from_build
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
NumberDef,
|
||||
is_running_from_build,
|
||||
is_in_tests,
|
||||
)
|
||||
from ayon_core.lib.execute import run_ayon_launcher_process
|
||||
from ayon_core.modules.royalrender.api import Api as rrApi
|
||||
from ayon_core.modules.royalrender.rr_job import (
|
||||
|
|
@ -22,7 +27,6 @@ from ayon_core.modules.royalrender.rr_job import (
|
|||
from ayon_core.pipeline import AYONPyblishPluginMixin
|
||||
from ayon_core.pipeline.publish import KnownPublishError
|
||||
from ayon_core.pipeline.publish.lib import get_published_workfile_instance
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
|
||||
|
||||
class BaseCreateRoyalRenderJob(pyblish.api.InstancePlugin,
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ from pprint import pformat
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io
|
||||
|
||||
|
||||
def collect(root,
|
||||
regex=None,
|
||||
|
|
@ -132,7 +130,6 @@ class CollectSequencesFromJob(pyblish.api.ContextPlugin):
|
|||
session = metadata.get("session")
|
||||
if session:
|
||||
self.log.info("setting session using metadata")
|
||||
legacy_io.Session.update(session)
|
||||
os.environ.update(session)
|
||||
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@ from ayon_core.modules.royalrender.rr_job import (
|
|||
get_rr_platform
|
||||
)
|
||||
from ayon_core.pipeline.publish import KnownPublishError
|
||||
from ayon_core.pipeline import (
|
||||
legacy_io,
|
||||
)
|
||||
from ayon_core.pipeline.farm.pyblish_functions import (
|
||||
create_skeleton_instance,
|
||||
create_instances_for_aov,
|
||||
|
|
@ -145,7 +142,6 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin,
|
|||
"intent": instance.context.data.get("intent"),
|
||||
"comment": instance.context.data.get("comment"),
|
||||
"job": attr.asdict(rr_job),
|
||||
"session": legacy_io.Session.copy(),
|
||||
"instances": instances
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
"""Core pipeline functionality"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import types
|
||||
import logging
|
||||
import platform
|
||||
|
|
@ -20,20 +19,20 @@ from ayon_core.client import (
|
|||
get_asset_name_identifier,
|
||||
get_ayon_server_api_connection,
|
||||
)
|
||||
from ayon_core.lib import is_in_tests
|
||||
from ayon_core.lib.events import emit_event
|
||||
from ayon_core.addon import load_addons, AddonsManager
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
|
||||
from .publish.lib import filter_pyblish_plugins
|
||||
from .anatomy import Anatomy
|
||||
from .template_data import get_template_data_with_names
|
||||
from .workfile import (
|
||||
get_workdir,
|
||||
get_workfile_template_key,
|
||||
get_custom_workfile_template_by_string_context,
|
||||
)
|
||||
from . import (
|
||||
legacy_io,
|
||||
register_loader_plugin_path,
|
||||
register_inventory_action_path,
|
||||
register_creator_plugin_path,
|
||||
|
|
@ -116,22 +115,17 @@ def install_host(host):
|
|||
# Make sure global AYON connection has set site id and version
|
||||
get_ayon_server_api_connection()
|
||||
|
||||
legacy_io.install()
|
||||
addons_manager = _get_addons_manager()
|
||||
|
||||
missing = list()
|
||||
for key in ("AVALON_PROJECT", "AVALON_ASSET"):
|
||||
if key not in legacy_io.Session:
|
||||
missing.append(key)
|
||||
project_name = os.getenv("AVALON_PROJECT")
|
||||
# WARNING: This might be an issue
|
||||
# - commented out because 'traypublisher' does not have set project
|
||||
# if not project_name:
|
||||
# raise ValueError(
|
||||
# "AVALON_PROJECT is missing in environment variables."
|
||||
# )
|
||||
|
||||
assert not missing, (
|
||||
"%s missing from environment, %s" % (
|
||||
", ".join(missing),
|
||||
json.dumps(legacy_io.Session, indent=4, sort_keys=True)
|
||||
))
|
||||
|
||||
project_name = legacy_io.Session["AVALON_PROJECT"]
|
||||
log.info("Activating %s.." % project_name)
|
||||
log.info("Activating {}..".format(project_name))
|
||||
|
||||
# Optional host install function
|
||||
if hasattr(host, "install"):
|
||||
|
|
@ -158,14 +152,13 @@ def install_host(host):
|
|||
print("Registering pyblish target: automated")
|
||||
pyblish.api.register_target("automated")
|
||||
|
||||
project_name = os.environ.get("AVALON_PROJECT")
|
||||
host_name = os.environ.get("AVALON_APP")
|
||||
|
||||
# Give option to handle host installation
|
||||
for addon in addons_manager.get_enabled_addons():
|
||||
addon.on_host_install(host, host_name, project_name)
|
||||
|
||||
install_openpype_plugins(project_name, host_name)
|
||||
install_ayon_plugins(project_name, host_name)
|
||||
|
||||
|
||||
def install_ayon_plugins(project_name=None, host_name=None):
|
||||
|
|
@ -256,8 +249,6 @@ def uninstall_host():
|
|||
|
||||
deregister_host()
|
||||
|
||||
legacy_io.uninstall()
|
||||
|
||||
log.info("Successfully uninstalled Avalon!")
|
||||
|
||||
|
||||
|
|
@ -482,13 +473,17 @@ def get_template_data_from_session(session=None, system_settings=None):
|
|||
Dict[str, Any]: All available data from session.
|
||||
"""
|
||||
|
||||
if session is None:
|
||||
session = legacy_io.Session
|
||||
|
||||
project_name = session["AVALON_PROJECT"]
|
||||
asset_name = session["AVALON_ASSET"]
|
||||
task_name = session["AVALON_TASK"]
|
||||
host_name = session["AVALON_APP"]
|
||||
if session is not None:
|
||||
project_name = session["AVALON_PROJECT"]
|
||||
asset_name = session["AVALON_ASSET"]
|
||||
task_name = session["AVALON_TASK"]
|
||||
host_name = session["AVALON_APP"]
|
||||
else:
|
||||
context = get_current_context()
|
||||
project_name = context["project_name"]
|
||||
asset_name = context["asset_name"]
|
||||
task_name = context["task_name"]
|
||||
host_name = get_current_host_name()
|
||||
|
||||
return get_template_data_with_names(
|
||||
project_name, asset_name, task_name, host_name, system_settings
|
||||
|
|
@ -529,10 +524,12 @@ def get_workdir_from_session(session=None, template_key=None):
|
|||
str: Workdir path.
|
||||
"""
|
||||
|
||||
if session is None:
|
||||
session = legacy_io.Session
|
||||
project_name = session["AVALON_PROJECT"]
|
||||
host_name = session["AVALON_APP"]
|
||||
if session is not None:
|
||||
project_name = session["AVALON_PROJECT"]
|
||||
host_name = session["AVALON_APP"]
|
||||
else:
|
||||
project_name = get_current_project_name()
|
||||
host_name = get_current_host_name()
|
||||
template_data = get_template_data_from_session(session)
|
||||
|
||||
if not template_key:
|
||||
|
|
@ -556,86 +553,39 @@ def get_custom_workfile_template_from_session(
|
|||
):
|
||||
"""Filter and fill workfile template profiles by current context.
|
||||
|
||||
Current context is defined by `legacy_io.Session`. That's why this
|
||||
function should be used only inside host where context is set and stable.
|
||||
This function cab be used only inside host where context is set.
|
||||
|
||||
Args:
|
||||
session (Union[None, Dict[str, str]]): Session from which are taken
|
||||
session (Optional[Dict[str, str]]): Session from which are taken
|
||||
data.
|
||||
project_settings(Dict[str, Any]): Template profiles from settings.
|
||||
project_settings(Optional[Dict[str, Any]]): Project settings.
|
||||
|
||||
Returns:
|
||||
str: Path to template or None if none of profiles match current
|
||||
context. (Existence of formatted path is not validated.)
|
||||
"""
|
||||
|
||||
if session is None:
|
||||
session = legacy_io.Session
|
||||
if session is not None:
|
||||
project_name = session["AVALON_PROJECT"]
|
||||
asset_name = session["AVALON_ASSET"]
|
||||
task_name = session["AVALON_TASK"]
|
||||
host_name = session["AVALON_APP"]
|
||||
else:
|
||||
context = get_current_context()
|
||||
project_name = context["project_name"]
|
||||
asset_name = context["asset_name"]
|
||||
task_name = context["task_name"]
|
||||
host_name = get_current_host_name()
|
||||
|
||||
return get_custom_workfile_template_by_string_context(
|
||||
session["AVALON_PROJECT"],
|
||||
session["AVALON_ASSET"],
|
||||
session["AVALON_TASK"],
|
||||
session["AVALON_APP"],
|
||||
project_name,
|
||||
asset_name,
|
||||
task_name,
|
||||
host_name,
|
||||
project_settings=project_settings
|
||||
)
|
||||
|
||||
|
||||
def compute_session_changes(
|
||||
session, asset_doc, task_name, template_key=None
|
||||
):
|
||||
"""Compute the changes for a session object on task under asset.
|
||||
|
||||
Function does not change the session object, only returns changes.
|
||||
|
||||
Args:
|
||||
session (Dict[str, str]): The initial session to compute changes to.
|
||||
This is required for computing the full Work Directory, as that
|
||||
also depends on the values that haven't changed.
|
||||
asset_doc (Dict[str, Any]): Asset document to switch to.
|
||||
task_name (str): Name of task to switch to.
|
||||
template_key (Union[str, None]): Prepare workfile template key in
|
||||
anatomy templates.
|
||||
|
||||
Returns:
|
||||
Dict[str, str]: Changes in the Session dictionary.
|
||||
"""
|
||||
|
||||
# Get asset document and asset
|
||||
if not asset_doc:
|
||||
task_name = None
|
||||
asset_name = None
|
||||
else:
|
||||
asset_name = get_asset_name_identifier(asset_doc)
|
||||
|
||||
# Detect any changes compared session
|
||||
mapping = {
|
||||
"AVALON_ASSET": asset_name,
|
||||
"AVALON_TASK": task_name,
|
||||
}
|
||||
changes = {
|
||||
key: value
|
||||
for key, value in mapping.items()
|
||||
if value != session.get(key)
|
||||
}
|
||||
if not changes:
|
||||
return changes
|
||||
|
||||
# Compute work directory (with the temporary changed session so far)
|
||||
changed_session = session.copy()
|
||||
changed_session.update(changes)
|
||||
|
||||
workdir = None
|
||||
if asset_doc:
|
||||
workdir = get_workdir_from_session(
|
||||
changed_session, template_key
|
||||
)
|
||||
|
||||
changes["AVALON_WORKDIR"] = workdir
|
||||
|
||||
return changes
|
||||
|
||||
|
||||
def change_current_context(asset_doc, task_name, template_key=None):
|
||||
"""Update active Session to a new task work area.
|
||||
|
||||
|
|
@ -651,32 +601,47 @@ def change_current_context(asset_doc, task_name, template_key=None):
|
|||
Dict[str, str]: The changed key, values in the current Session.
|
||||
"""
|
||||
|
||||
changes = compute_session_changes(
|
||||
legacy_io.Session,
|
||||
asset_doc,
|
||||
task_name,
|
||||
template_key=template_key
|
||||
)
|
||||
project_name = get_current_project_name()
|
||||
workdir = None
|
||||
if asset_doc:
|
||||
project_doc = get_project(project_name)
|
||||
host_name = get_current_host_name()
|
||||
workdir = get_workdir(
|
||||
project_doc,
|
||||
asset_doc,
|
||||
task_name,
|
||||
host_name,
|
||||
template_key=template_key
|
||||
)
|
||||
|
||||
folder_path = get_asset_name_identifier(asset_doc)
|
||||
envs = {
|
||||
"AVALON_PROJECT": project_name,
|
||||
"AVALON_ASSET": folder_path,
|
||||
"AVALON_TASK": task_name,
|
||||
"AVALON_WORKDIR": workdir,
|
||||
}
|
||||
|
||||
# Update the Session and environments. Pop from environments all keys with
|
||||
# value set to None.
|
||||
for key, value in changes.items():
|
||||
legacy_io.Session[key] = value
|
||||
for key, value in envs.items():
|
||||
if value is None:
|
||||
os.environ.pop(key, None)
|
||||
else:
|
||||
os.environ[key] = value
|
||||
|
||||
data = changes.copy()
|
||||
data = envs.copy()
|
||||
|
||||
# Convert env keys to human readable keys
|
||||
data["project_name"] = legacy_io.Session["AVALON_PROJECT"]
|
||||
data["asset_name"] = legacy_io.Session["AVALON_ASSET"]
|
||||
data["task_name"] = legacy_io.Session["AVALON_TASK"]
|
||||
data["project_name"] = project_name
|
||||
data["asset_name"] = get_asset_name_identifier(asset_doc)
|
||||
data["task_name"] = task_name
|
||||
data["workdir_path"] = workdir
|
||||
|
||||
# Emit session change
|
||||
emit_event("taskChanged", data)
|
||||
|
||||
return changes
|
||||
return data
|
||||
|
||||
|
||||
def get_process_id():
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ from ayon_core.lib.attribute_definitions import (
|
|||
get_default_values,
|
||||
)
|
||||
from ayon_core.host import IPublishHost, IWorkfileHost
|
||||
from ayon_core.pipeline import legacy_io, Anatomy
|
||||
from ayon_core.pipeline import Anatomy
|
||||
from ayon_core.pipeline.plugin_discover import DiscoverResult
|
||||
|
||||
from .creator_plugins import (
|
||||
|
|
@ -1684,25 +1684,16 @@ class CreateContext:
|
|||
if isinstance(self.host, IWorkfileHost):
|
||||
workfile_path = self.host.get_current_workfile()
|
||||
|
||||
# --- TODO remove these conditions ---
|
||||
if not project_name:
|
||||
project_name = legacy_io.Session.get("AVALON_PROJECT")
|
||||
if not asset_name:
|
||||
asset_name = legacy_io.Session.get("AVALON_ASSET")
|
||||
if not task_name:
|
||||
task_name = legacy_io.Session.get("AVALON_TASK")
|
||||
# ---
|
||||
return project_name, asset_name, task_name, workfile_path
|
||||
|
||||
def reset_current_context(self):
|
||||
"""Refresh current context.
|
||||
|
||||
Reset is based on optional host implementation of `get_current_context`
|
||||
function or using `legacy_io.Session`.
|
||||
function.
|
||||
|
||||
Some hosts have ability to change context file without using workfiles
|
||||
tool but that change is not propagated to 'legacy_io.Session'
|
||||
nor 'os.environ'.
|
||||
tool but that change is not propagated to 'os.environ'.
|
||||
|
||||
Todos:
|
||||
UI: Current context should be also checked on save - compare
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import os
|
|||
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.lib import filter_profiles, prepare_template_data
|
||||
from ayon_core.pipeline import legacy_io
|
||||
|
||||
from .constants import DEFAULT_SUBSET_TEMPLATE
|
||||
|
||||
|
|
@ -135,7 +134,7 @@ def get_subset_name(
|
|||
family = family.rsplit(".", 1)[-1]
|
||||
|
||||
if project_name is None:
|
||||
project_name = legacy_io.Session["AVALON_PROJECT"]
|
||||
project_name = os.environ.get("AVALON_PROJECT")
|
||||
|
||||
asset_tasks = asset_doc.get("data", {}).get("tasks") or {}
|
||||
task_info = asset_tasks.get(task_name) or {}
|
||||
|
|
|
|||
|
|
@ -1,109 +1,36 @@
|
|||
"""Wrapper around interactions with the database"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import functools
|
||||
|
||||
from . import schema
|
||||
|
||||
module = sys.modules[__name__]
|
||||
from ayon_core.pipeline import get_current_project_name
|
||||
|
||||
Session = {}
|
||||
_is_installed = False
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
SESSION_CONTEXT_KEYS = (
|
||||
# Name of current Project
|
||||
"AVALON_PROJECT",
|
||||
# Name of current Asset
|
||||
"AVALON_ASSET",
|
||||
# Name of current task
|
||||
"AVALON_TASK",
|
||||
# Name of current app
|
||||
"AVALON_APP",
|
||||
# Path to working directory
|
||||
"AVALON_WORKDIR",
|
||||
# Optional path to scenes directory (see Work Files API)
|
||||
"AVALON_SCENEDIR"
|
||||
log.warning(
|
||||
"DEPRECATION WARNING: 'legacy_io' is deprecated and will be removed in"
|
||||
" future versions of ayon-core addon."
|
||||
"\nReading from Session won't give you updated information and changing"
|
||||
" values won't affect global state of a process."
|
||||
)
|
||||
|
||||
|
||||
def session_data_from_environment(context_keys=False):
|
||||
session_data = {}
|
||||
if context_keys:
|
||||
for key in SESSION_CONTEXT_KEYS:
|
||||
value = os.environ.get(key)
|
||||
session_data[key] = value or ""
|
||||
else:
|
||||
for key in SESSION_CONTEXT_KEYS:
|
||||
session_data[key] = None
|
||||
|
||||
for key, default_value in (
|
||||
# Name of Avalon in graphical user interfaces
|
||||
# Use this to customise the visual appearance of Avalon
|
||||
# to better integrate with your surrounding pipeline
|
||||
("AVALON_LABEL", "Avalon"),
|
||||
|
||||
# Used during any connections to the outside world
|
||||
("AVALON_TIMEOUT", "1000"),
|
||||
|
||||
# Name of database used in MongoDB
|
||||
("AVALON_DB", "avalon"),
|
||||
):
|
||||
value = os.environ.get(key) or default_value
|
||||
if value is not None:
|
||||
session_data[key] = value
|
||||
|
||||
return session_data
|
||||
return {}
|
||||
|
||||
|
||||
def is_installed():
|
||||
return module._is_installed
|
||||
return False
|
||||
|
||||
|
||||
def install():
|
||||
"""Establish a persistent connection to the database"""
|
||||
if is_installed():
|
||||
return
|
||||
|
||||
session = session_data_from_environment(context_keys=True)
|
||||
|
||||
session["schema"] = "openpype:session-4.0"
|
||||
try:
|
||||
schema.validate(session)
|
||||
except schema.ValidationError as e:
|
||||
# TODO(marcus): Make this mandatory
|
||||
log.warning(e)
|
||||
|
||||
Session.update(session)
|
||||
|
||||
module._is_installed = True
|
||||
pass
|
||||
|
||||
|
||||
def uninstall():
|
||||
"""Close any connection to the database.
|
||||
|
||||
Deprecated:
|
||||
This function does nothing should be removed.
|
||||
"""
|
||||
module._is_installed = False
|
||||
pass
|
||||
|
||||
|
||||
def requires_install(func):
|
||||
@functools.wraps(func)
|
||||
def decorated(*args, **kwargs):
|
||||
if not is_installed():
|
||||
install()
|
||||
return func(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
|
||||
@requires_install
|
||||
def active_project(*args, **kwargs):
|
||||
return Session["AVALON_PROJECT"]
|
||||
return get_current_project_name()
|
||||
|
||||
|
||||
def current_project(*args, **kwargs):
|
||||
return Session.get("AVALON_PROJECT")
|
||||
return get_current_project_name()
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@ import os
|
|||
import logging
|
||||
|
||||
from ayon_core.settings import get_system_settings, get_project_settings
|
||||
from ayon_core.pipeline import (
|
||||
schema,
|
||||
legacy_io,
|
||||
)
|
||||
from ayon_core.pipeline import schema
|
||||
from ayon_core.pipeline.plugin_discover import (
|
||||
discover,
|
||||
register_plugin,
|
||||
|
|
|
|||
|
|
@ -553,6 +553,12 @@ class AbstractTemplateBuilder(object):
|
|||
|
||||
self.clear_shared_populate_data()
|
||||
|
||||
def open_template(self):
|
||||
"""Open template file with registered host."""
|
||||
template_preset = self.get_template_preset()
|
||||
template_path = template_preset["path"]
|
||||
self.host.open_file(template_path)
|
||||
|
||||
@abstractmethod
|
||||
def import_template(self, template_path):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import shutil
|
|||
import pyblish.api
|
||||
import re
|
||||
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.lib import is_in_tests
|
||||
|
||||
|
||||
class CleanUp(pyblish.api.InstancePlugin):
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import os
|
|||
import pyblish.api
|
||||
|
||||
from ayon_core.host import IPublishHost
|
||||
from ayon_core.pipeline import legacy_io, registered_host
|
||||
from ayon_core.pipeline import registered_host
|
||||
from ayon_core.pipeline.create import CreateContext
|
||||
|
||||
|
||||
|
|
@ -61,8 +61,10 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin):
|
|||
("AVALON_ASSET", asset_name),
|
||||
("AVALON_TASK", task_name)
|
||||
):
|
||||
legacy_io.Session[key] = value
|
||||
os.environ[key] = value
|
||||
if value is None:
|
||||
os.environ.pop(key, None)
|
||||
else:
|
||||
os.environ[key] = value
|
||||
|
||||
def create_instance(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import json
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import legacy_io, KnownPublishError
|
||||
from ayon_core.pipeline import KnownPublishError
|
||||
from ayon_core.pipeline.publish.lib import add_repre_files_for_cleanup
|
||||
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin):
|
|||
# validate basic necessary data
|
||||
data_err = "invalid json file - missing data"
|
||||
required = ["asset", "user", "comment",
|
||||
"job", "instances", "session", "version"]
|
||||
"job", "instances", "version"]
|
||||
assert all(elem in data.keys() for elem in required), data_err
|
||||
|
||||
# set context by first json file
|
||||
|
|
@ -144,7 +144,7 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin):
|
|||
os.environ.get("AYON_PUBLISH_DATA")
|
||||
or os.environ.get("OPENPYPE_PUBLISH_DATA")
|
||||
)
|
||||
if publish_data_paths:
|
||||
if not publish_data_paths:
|
||||
raise KnownPublishError("Missing `AYON_PUBLISH_DATA`")
|
||||
|
||||
# QUESTION
|
||||
|
|
@ -165,24 +165,28 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin):
|
|||
path = anatomy.fill_root(path)
|
||||
data = self._load_json(path)
|
||||
assert data, "failed to load json file"
|
||||
if not session_is_set:
|
||||
session_data = data["session"]
|
||||
remapped = anatomy.roots_obj.path_remapper(
|
||||
session_data["AVALON_WORKDIR"]
|
||||
)
|
||||
if remapped:
|
||||
session_data["AVALON_WORKDIR"] = remapped
|
||||
|
||||
self.log.debug("Setting session using data from file")
|
||||
legacy_io.Session.update(session_data)
|
||||
os.environ.update(session_data)
|
||||
session_data = data.get("session")
|
||||
if not session_is_set and session_data:
|
||||
session_is_set = True
|
||||
self.log.debug("Setting session using data from file")
|
||||
os.environ.update(session_data)
|
||||
|
||||
staging_dir_persistent = self._process_path(data, anatomy)
|
||||
if not staging_dir_persistent:
|
||||
context.data["cleanupFullPaths"].append(path)
|
||||
context.data["cleanupEmptyDirs"].append(
|
||||
os.path.dirname(path)
|
||||
)
|
||||
|
||||
# Remap workdir if it's set
|
||||
workdir = os.getenv("AVALON_WORKDIR")
|
||||
remapped_workdir = None
|
||||
if workdir:
|
||||
remapped_workdir = anatomy.roots_obj.path_remapper(
|
||||
os.getenv("AVALON_WORKDIR")
|
||||
)
|
||||
if remapped_workdir:
|
||||
os.environ["AVALON_WORKDIR"] = remapped_workdir
|
||||
except Exception as e:
|
||||
self.log.error(e, exc_info=True)
|
||||
raise Exception("Error") from e
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import os
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.lib import get_version_from_path
|
||||
from ayon_core.tests.lib import is_in_tests
|
||||
from ayon_core.lib import get_version_from_path, is_in_tests
|
||||
from ayon_core.pipeline import KnownPublishError
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
Tests for Pype
|
||||
--------------
|
||||
Trigger by:
|
||||
`pype test --pype`
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import tempfile
|
||||
import contextlib
|
||||
|
||||
import pyblish
|
||||
import pyblish.plugin
|
||||
from pyblish.vendor import six
|
||||
|
||||
|
||||
# Setup
|
||||
HOST = 'python'
|
||||
FAMILY = 'test.family'
|
||||
|
||||
REGISTERED = pyblish.plugin.registered_paths()
|
||||
PACKAGEPATH = pyblish.lib.main_package_path()
|
||||
ENVIRONMENT = os.environ.get("PYBLISHPLUGINPATH", "")
|
||||
PLUGINPATH = os.path.join(PACKAGEPATH, '..', 'tests', 'plugins')
|
||||
|
||||
|
||||
def setup():
|
||||
pyblish.plugin.deregister_all_paths()
|
||||
|
||||
|
||||
def setup_empty():
|
||||
"""Disable all plug-ins"""
|
||||
setup()
|
||||
pyblish.plugin.deregister_all_plugins()
|
||||
pyblish.plugin.deregister_all_paths()
|
||||
pyblish.plugin.deregister_all_hosts()
|
||||
pyblish.plugin.deregister_all_callbacks()
|
||||
pyblish.plugin.deregister_all_targets()
|
||||
pyblish.api.deregister_all_discovery_filters()
|
||||
|
||||
|
||||
def teardown():
|
||||
"""Restore previously REGISTERED paths"""
|
||||
|
||||
pyblish.plugin.deregister_all_paths()
|
||||
for path in REGISTERED:
|
||||
pyblish.plugin.register_plugin_path(path)
|
||||
|
||||
os.environ["PYBLISHPLUGINPATH"] = ENVIRONMENT
|
||||
pyblish.api.deregister_all_plugins()
|
||||
pyblish.api.deregister_all_hosts()
|
||||
pyblish.api.deregister_all_discovery_filters()
|
||||
pyblish.api.deregister_test()
|
||||
pyblish.api.__init__()
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def captured_stdout():
|
||||
"""Temporarily reassign stdout to a local variable"""
|
||||
try:
|
||||
sys.stdout = six.StringIO()
|
||||
yield sys.stdout
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def captured_stderr():
|
||||
"""Temporarily reassign stderr to a local variable"""
|
||||
try:
|
||||
sys.stderr = six.StringIO()
|
||||
yield sys.stderr
|
||||
finally:
|
||||
sys.stderr = sys.__stderr__
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def tempdir():
|
||||
"""Provide path to temporary directory"""
|
||||
try:
|
||||
tempdir = tempfile.mkdtemp()
|
||||
yield tempdir
|
||||
finally:
|
||||
shutil.rmtree(tempdir)
|
||||
|
||||
|
||||
def is_in_tests():
|
||||
"""Returns if process is running in automatic tests mode.
|
||||
|
||||
In tests mode different source DB is used, some plugins might be disabled
|
||||
etc.
|
||||
"""
|
||||
return os.environ.get("IS_TEST") == '1'
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
import pymongo
|
||||
import bson
|
||||
import random
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
|
||||
class TestPerformance():
|
||||
'''
|
||||
Class for testing performance of representation and their 'files'
|
||||
parts.
|
||||
Discussion is if embedded array:
|
||||
'files' : [ {'_id': '1111', 'path':'....},
|
||||
{'_id'...}]
|
||||
OR documents:
|
||||
'files' : {
|
||||
'1111': {'path':'....'},
|
||||
'2222': {'path':'...'}
|
||||
}
|
||||
is faster.
|
||||
|
||||
Current results:
|
||||
without additional partial index documents is 3x faster
|
||||
With index is array 50x faster then document
|
||||
|
||||
Partial index something like:
|
||||
db.getCollection('performance_test').createIndex
|
||||
({'files._id': 1},
|
||||
{partialFilterExpresion: {'files': {'$exists': true}}})
|
||||
!DIDNT work for me, had to create manually in Compass
|
||||
|
||||
'''
|
||||
|
||||
MONGO_URL = 'mongodb://localhost:27017'
|
||||
MONGO_DB = 'performance_test'
|
||||
MONGO_COLLECTION = 'performance_test'
|
||||
|
||||
MAX_FILE_SIZE_B = 5000
|
||||
MAX_NUMBER_OF_SITES = 50
|
||||
ROOT_DIR = "C:/projects"
|
||||
|
||||
inserted_ids = []
|
||||
|
||||
def __init__(self, version='array'):
|
||||
'''
|
||||
It creates and fills collection, based on value of 'version'.
|
||||
|
||||
:param version: 'array' - files as embedded array,
|
||||
'doc' - as document
|
||||
'''
|
||||
self.client = pymongo.MongoClient(self.MONGO_URL)
|
||||
self.db = self.client[self.MONGO_DB]
|
||||
self.collection_name = self.MONGO_COLLECTION
|
||||
|
||||
self.version = version
|
||||
|
||||
if self.version != 'array':
|
||||
self.collection_name = self.MONGO_COLLECTION + '_doc'
|
||||
|
||||
self.collection = self.db[self.collection_name]
|
||||
|
||||
self.ids = [] # for testing
|
||||
self.inserted_ids = []
|
||||
|
||||
def prepare(self, no_of_records=100000, create_files=False):
|
||||
'''
|
||||
Produce 'no_of_records' of representations with 'files' segment.
|
||||
It depends on 'version' value in constructor, 'arrray' or 'doc'
|
||||
:return:
|
||||
'''
|
||||
print('Purging {} collection'.format(self.collection_name))
|
||||
self.collection.delete_many({})
|
||||
|
||||
id = bson.objectid.ObjectId()
|
||||
|
||||
insert_recs = []
|
||||
for i in range(no_of_records):
|
||||
file_id = bson.objectid.ObjectId()
|
||||
file_id2 = bson.objectid.ObjectId()
|
||||
file_id3 = bson.objectid.ObjectId()
|
||||
|
||||
self.inserted_ids.extend([file_id, file_id2, file_id3])
|
||||
version_str = "v{:03d}".format(i + 1)
|
||||
file_name = "test_Cylinder_workfileLookdev_{}.mb".\
|
||||
format(version_str)
|
||||
|
||||
document = {"files": self.get_files(self.version, i + 1,
|
||||
file_id, file_id2, file_id3,
|
||||
create_files)
|
||||
,
|
||||
"context": {
|
||||
"subset": "workfileLookdev",
|
||||
"username": "petrk",
|
||||
"task": "lookdev",
|
||||
"family": "workfile",
|
||||
"hierarchy": "Assets",
|
||||
"project": {"code": "test", "name": "Test"},
|
||||
"version": i + 1,
|
||||
"asset": "Cylinder",
|
||||
"representation": "mb",
|
||||
"root": self.ROOT_DIR
|
||||
},
|
||||
"dependencies": [],
|
||||
"name": "mb",
|
||||
"parent": {"oid": '{}'.format(id)},
|
||||
"data": {
|
||||
"path": "C:\\projects\\test_performance\\Assets\\Cylinder\\publish\\workfile\\workfileLookdev\\{}\\{}".format(version_str, file_name), # noqa: E501
|
||||
"template": "{root[work]}\\{project[name]}\\{hierarchy}\\{asset}\\publish\\{family}\\{subset}\\v{version:0>3}\\{project[code]}_{asset}_{subset}_v{version:0>3}<_{output}><.{frame:0>4}>.{representation}" # noqa: E501
|
||||
},
|
||||
"type": "representation",
|
||||
"schema": "openpype:representation-2.0"
|
||||
}
|
||||
|
||||
insert_recs.append(document)
|
||||
|
||||
print('Prepared {} records in {} collection'.
|
||||
format(no_of_records, self.collection_name))
|
||||
|
||||
self.collection.insert_many(insert_recs)
|
||||
# TODO refactore to produce real array and not needeing ugly regex
|
||||
self.collection.insert_one({"inserted_id": self.inserted_ids})
|
||||
print('-' * 50)
|
||||
|
||||
def run(self, queries=1000, loops=3):
|
||||
'''
|
||||
Run X'queries' that are searching collection Y'loops' times
|
||||
:param queries: how many times do ..find(...)
|
||||
:param loops: loop of testing X queries
|
||||
:return: None
|
||||
'''
|
||||
print('Testing version {} on {}'.format(self.version,
|
||||
self.collection_name))
|
||||
print('Queries rung {} in {} loops'.format(queries, loops))
|
||||
|
||||
inserted_ids = list(self.collection.
|
||||
find({"inserted_id": {"$exists": True}}))
|
||||
import re
|
||||
self.ids = re.findall("'[0-9a-z]*'", str(inserted_ids))
|
||||
|
||||
import time
|
||||
|
||||
found_cnt = 0
|
||||
for _ in range(loops):
|
||||
print('Starting loop {}'.format(_))
|
||||
start = time.time()
|
||||
for _ in range(queries):
|
||||
# val = random.choice(self.ids)
|
||||
# val = val.replace("'", '')
|
||||
val = random.randint(0, 50)
|
||||
print(val)
|
||||
|
||||
if (self.version == 'array'):
|
||||
# prepared for partial index, without 'files': exists
|
||||
# wont engage
|
||||
found = self.collection.\
|
||||
find({'files': {"$exists": True},
|
||||
'files.sites.name': "local_{}".format(val)}).\
|
||||
count()
|
||||
else:
|
||||
key = "files.{}".format(val)
|
||||
found = self.collection.find_one({key: {"$exists": True}})
|
||||
print("found {} records".format(found))
|
||||
# if found:
|
||||
# found_cnt += len(list(found))
|
||||
|
||||
end = time.time()
|
||||
print('duration per loop {}'.format(end - start))
|
||||
print("found_cnt {}".format(found_cnt))
|
||||
|
||||
def get_files(self, mode, i, file_id, file_id2, file_id3,
|
||||
create_files=False):
|
||||
'''
|
||||
Wrapper to decide if 'array' or document version should be used
|
||||
:param mode: 'array'|'doc'
|
||||
:param i: step number
|
||||
:param file_id: ObjectId of first dummy file
|
||||
:param file_id2: ..
|
||||
:param file_id3: ..
|
||||
:return:
|
||||
'''
|
||||
if mode == 'array':
|
||||
return self.get_files_array(i, file_id, file_id2, file_id3,
|
||||
create_files)
|
||||
else:
|
||||
return self.get_files_doc(i, file_id, file_id2, file_id3)
|
||||
|
||||
def get_files_array(self, i, file_id, file_id2, file_id3,
|
||||
create_files=False):
|
||||
ret = [
|
||||
{
|
||||
"path": "{root[work]}" + "{root[work]}/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_A_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501
|
||||
"_id": '{}'.format(file_id),
|
||||
"hash": "temphash",
|
||||
"sites": self.get_sites(self.MAX_NUMBER_OF_SITES),
|
||||
"size": random.randint(0, self.MAX_FILE_SIZE_B)
|
||||
},
|
||||
{
|
||||
"path": "{root[work]}" + "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_B_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501
|
||||
"_id": '{}'.format(file_id2),
|
||||
"hash": "temphash",
|
||||
"sites": self.get_sites(self.MAX_NUMBER_OF_SITES),
|
||||
"size": random.randint(0, self.MAX_FILE_SIZE_B)
|
||||
},
|
||||
{
|
||||
"path": "{root[work]}" + "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_C_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501
|
||||
"_id": '{}'.format(file_id3),
|
||||
"hash": "temphash",
|
||||
"sites": self.get_sites(self.MAX_NUMBER_OF_SITES),
|
||||
"size": random.randint(0, self.MAX_FILE_SIZE_B)
|
||||
}
|
||||
|
||||
]
|
||||
if create_files:
|
||||
for f in ret:
|
||||
path = f.get("path").replace("{root[work]}", self.ROOT_DIR)
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(path, 'wb') as fp:
|
||||
fp.write(os.urandom(f.get("size")))
|
||||
|
||||
return ret
|
||||
|
||||
def get_files_doc(self, i, file_id, file_id2, file_id3):
|
||||
ret = {}
|
||||
ret['{}'.format(file_id)] = {
|
||||
"path": "{root[work]}" +
|
||||
"/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501
|
||||
"v{:03d}/test_CylinderA_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501
|
||||
"hash": "temphash",
|
||||
"sites": ["studio"],
|
||||
"size": 87236
|
||||
}
|
||||
|
||||
ret['{}'.format(file_id2)] = {
|
||||
"path": "{root[work]}" +
|
||||
"/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501
|
||||
"v{:03d}/test_CylinderB_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501
|
||||
"hash": "temphash",
|
||||
"sites": ["studio"],
|
||||
"size": 87236
|
||||
}
|
||||
ret['{}'.format(file_id3)] = {
|
||||
"path": "{root[work]}" +
|
||||
"/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501
|
||||
"v{:03d}/test_CylinderC_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501
|
||||
"hash": "temphash",
|
||||
"sites": ["studio"],
|
||||
"size": 87236
|
||||
}
|
||||
|
||||
return ret
|
||||
|
||||
def get_sites(self, number_of_sites=50):
|
||||
"""
|
||||
Return array of sites declaration.
|
||||
Currently on 1st site has "created_dt" fillled, which should
|
||||
trigger upload to 'gdrive' site.
|
||||
'gdrive' site is appended, its destination for syncing for
|
||||
Sync Server
|
||||
Args:
|
||||
number_of_sites:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
sites = []
|
||||
for i in range(number_of_sites):
|
||||
site = {'name': "local_{}".format(i)}
|
||||
# do not create null 'created_dt' field, Mongo doesnt like it
|
||||
if i == 0:
|
||||
site['created_dt'] = datetime.now()
|
||||
|
||||
sites.append(site)
|
||||
|
||||
sites.append({'name': "gdrive"})
|
||||
|
||||
return sites
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
tp = TestPerformance('array')
|
||||
tp.prepare(no_of_records=10000, create_files=True)
|
||||
# tp.run(10, 3)
|
||||
|
||||
# print('-'*50)
|
||||
#
|
||||
# tp = TestPerformance('doc')
|
||||
# tp.prepare() # enable to prepare data
|
||||
# tp.run(1000, 3)
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
from ayon_core.pipeline import (
|
||||
install_host,
|
||||
LegacyCreator,
|
||||
register_creator_plugin,
|
||||
discover_creator_plugins,
|
||||
)
|
||||
|
||||
|
||||
class MyTestCreator(LegacyCreator):
|
||||
|
||||
my_test_property = "A"
|
||||
|
||||
def __init__(self, name, asset, options=None, data=None):
|
||||
super(MyTestCreator, self).__init__(self, name, asset,
|
||||
options=None, data=None)
|
||||
|
||||
|
||||
# this is hack like no other - we need to inject our own avalon host
|
||||
# and bypass all its validation. Avalon hosts are modules that needs
|
||||
# `ls` callable as attribute. Voila:
|
||||
class Test:
|
||||
__name__ = "test"
|
||||
ls = len
|
||||
|
||||
@staticmethod
|
||||
def install():
|
||||
register_creator_plugin(MyTestCreator)
|
||||
|
||||
|
||||
def test_avalon_plugin_presets(monkeypatch, printer):
|
||||
install_host(Test)
|
||||
|
||||
plugins = discover_creator_plugins()
|
||||
printer("Test if we got our test plugin")
|
||||
assert MyTestCreator in plugins
|
||||
for p in plugins:
|
||||
if p.__name__ == "MyTestCreator":
|
||||
printer("Test if we have overridden existing property")
|
||||
assert p.my_test_property == "B"
|
||||
printer("Test if we have overridden superclass property")
|
||||
assert p.active is False
|
||||
printer("Test if we have added new property")
|
||||
assert p.new_property == "new"
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# Test for backward compatibility of restructure of lib.py into lib library
|
||||
# Contains simple imports that should still work
|
||||
|
||||
|
||||
def test_backward_compatibility(printer):
|
||||
printer("Test if imports still work")
|
||||
try:
|
||||
from ayon_core.lib import execute_hook
|
||||
from ayon_core.lib import PypeHook
|
||||
|
||||
from ayon_core.lib import ApplicationLaunchFailed
|
||||
|
||||
from ayon_core.lib import get_ffmpeg_tool_path
|
||||
from ayon_core.lib import get_last_version_from_path
|
||||
from ayon_core.lib import get_paths_from_environ
|
||||
from ayon_core.lib import get_version_from_path
|
||||
from ayon_core.lib import version_up
|
||||
|
||||
from ayon_core.lib import get_ffprobe_streams
|
||||
|
||||
from ayon_core.lib import source_hash
|
||||
from ayon_core.lib import run_subprocess
|
||||
|
||||
except ImportError as e:
|
||||
raise
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import os
|
||||
import pyblish.api
|
||||
import pyblish.util
|
||||
import pyblish.plugin
|
||||
from ayon_core.pipeline.publish.lib import filter_pyblish_plugins
|
||||
from . import lib
|
||||
|
||||
|
||||
def test_pyblish_plugin_filter_modifier(printer, monkeypatch):
|
||||
"""
|
||||
Test if pyblish filter can filter and modify plugins on-the-fly.
|
||||
"""
|
||||
|
||||
lib.setup_empty()
|
||||
monkeypatch.setitem(os.environ, 'PYBLISHPLUGINPATH', '')
|
||||
plugins = pyblish.api.registered_plugins()
|
||||
printer("Test if we have no registered plugins")
|
||||
assert len(plugins) == 0
|
||||
paths = pyblish.api.registered_paths()
|
||||
printer("Test if we have no registered plugin paths")
|
||||
assert len(paths) == 0
|
||||
|
||||
class MyTestPlugin(pyblish.api.InstancePlugin):
|
||||
my_test_property = 1
|
||||
label = "Collect Renderable Camera(s)"
|
||||
hosts = ["test"]
|
||||
families = ["default"]
|
||||
|
||||
pyblish.api.register_host("test")
|
||||
pyblish.api.register_plugin(MyTestPlugin)
|
||||
pyblish.api.register_discovery_filter(filter_pyblish_plugins)
|
||||
plugins = pyblish.api.discover()
|
||||
|
||||
printer("Test if only one plugin was discovered")
|
||||
assert len(plugins) == 1
|
||||
printer("Test if properties are modified correctly")
|
||||
assert plugins[0].label == "loaded from preset"
|
||||
assert plugins[0].families == ["changed", "by", "preset"]
|
||||
assert plugins[0].optional is True
|
||||
|
||||
lib.teardown()
|
||||
|
||||
|
||||
def test_pyblish_plugin_filter_removal(monkeypatch):
|
||||
""" Test that plugin can be removed by filter """
|
||||
lib.setup_empty()
|
||||
monkeypatch.setitem(os.environ, 'PYBLISHPLUGINPATH', '')
|
||||
plugins = pyblish.api.registered_plugins()
|
||||
|
||||
class MyTestRemovedPlugin(pyblish.api.InstancePlugin):
|
||||
my_test_property = 1
|
||||
label = "Collect Renderable Camera(s)"
|
||||
hosts = ["test"]
|
||||
families = ["default"]
|
||||
|
||||
pyblish.api.register_host("test")
|
||||
pyblish.api.register_plugin(MyTestRemovedPlugin)
|
||||
pyblish.api.register_discovery_filter(filter_pyblish_plugins)
|
||||
plugins = pyblish.api.discover()
|
||||
assert len(plugins) == 0
|
||||
|
|
@ -21,7 +21,7 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget):
|
|||
|
||||
def __init__(self, controller, parent):
|
||||
self._controller = controller
|
||||
super(CreateWidgetAssetsWidget, self).__init__(None, parent)
|
||||
super(CreateWidgetAssetsWidget, self).__init__(parent)
|
||||
|
||||
self.set_refresh_btn_visibility(False)
|
||||
self.set_current_asset_btn_visibility(False)
|
||||
|
|
@ -31,6 +31,9 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget):
|
|||
|
||||
self._last_filter_height = None
|
||||
|
||||
def get_project_name(self):
|
||||
return self._controller.project_name
|
||||
|
||||
def get_selected_asset_name(self):
|
||||
selection_model = self._view.selectionModel()
|
||||
indexes = selection_model.selectedRows()
|
||||
|
|
@ -79,10 +82,10 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget):
|
|||
|
||||
def update_current_asset(self):
|
||||
# Hide set current asset if there is no one
|
||||
asset_name = self._get_current_session_asset()
|
||||
asset_name = self._get_current_asset_name()
|
||||
self.set_current_asset_btn_visibility(bool(asset_name))
|
||||
|
||||
def _get_current_session_asset(self):
|
||||
def _get_current_asset_name(self):
|
||||
return self._controller.current_asset_name
|
||||
|
||||
def _create_source_model(self):
|
||||
|
|
|
|||
|
|
@ -565,7 +565,7 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
self._last_thumbnail_path = None
|
||||
|
||||
def _on_current_session_context_request(self):
|
||||
self._assets_widget.set_current_session_asset()
|
||||
self._assets_widget.select_current_asset()
|
||||
task_name = self.current_task_name
|
||||
if task_name:
|
||||
self._tasks_widget.select_task_name(task_name)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
from qtpy import QtCore, QtGui
|
||||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
|
||||
from ayon_core.tools.utils.tasks_widget import TasksWidget, TASK_NAME_ROLE
|
||||
from ayon_core.tools.utils.views import DeselectableTreeView
|
||||
from ayon_core.tools.utils.lib import get_default_task_icon
|
||||
|
||||
TASK_NAME_ROLE = QtCore.Qt.UserRole + 1
|
||||
TASK_TYPE_ROLE = QtCore.Qt.UserRole + 2
|
||||
TASK_ORDER_ROLE = QtCore.Qt.UserRole + 3
|
||||
|
||||
|
||||
class TasksModel(QtGui.QStandardItemModel):
|
||||
"""Tasks model.
|
||||
|
|
@ -141,15 +145,159 @@ class TasksModel(QtGui.QStandardItemModel):
|
|||
return super(TasksModel, self).headerData(section, orientation, role)
|
||||
|
||||
|
||||
class CreateWidgetTasksWidget(TasksWidget):
|
||||
class TasksProxyModel(QtCore.QSortFilterProxyModel):
|
||||
def lessThan(self, x_index, y_index):
|
||||
x_order = x_index.data(TASK_ORDER_ROLE)
|
||||
y_order = y_index.data(TASK_ORDER_ROLE)
|
||||
if x_order is not None and y_order is not None:
|
||||
if x_order < y_order:
|
||||
return True
|
||||
if x_order > y_order:
|
||||
return False
|
||||
|
||||
elif x_order is None and y_order is not None:
|
||||
return True
|
||||
|
||||
elif y_order is None and x_order is not None:
|
||||
return False
|
||||
|
||||
x_name = x_index.data(QtCore.Qt.DisplayRole)
|
||||
y_name = y_index.data(QtCore.Qt.DisplayRole)
|
||||
if x_name == y_name:
|
||||
return True
|
||||
|
||||
if x_name == tuple(sorted((x_name, y_name)))[0]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class CreateWidgetTasksWidget(QtWidgets.QWidget):
|
||||
"""Widget showing active Tasks
|
||||
|
||||
Deprecated:
|
||||
This widget will be removed soon. Please do not use it in new code.
|
||||
"""
|
||||
|
||||
task_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, controller, parent):
|
||||
self._controller = controller
|
||||
super(CreateWidgetTasksWidget, self).__init__(None, parent)
|
||||
|
||||
self._enabled = None
|
||||
|
||||
def _create_source_model(self):
|
||||
return TasksModel(self._controller)
|
||||
super(CreateWidgetTasksWidget, self).__init__(parent)
|
||||
|
||||
tasks_view = DeselectableTreeView(self)
|
||||
tasks_view.setIndentation(0)
|
||||
tasks_view.setSortingEnabled(True)
|
||||
tasks_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
|
||||
header_view = tasks_view.header()
|
||||
header_view.setSortIndicator(0, QtCore.Qt.AscendingOrder)
|
||||
|
||||
tasks_model = TasksModel(self._controller)
|
||||
tasks_proxy = TasksProxyModel()
|
||||
tasks_proxy.setSourceModel(tasks_model)
|
||||
tasks_view.setModel(tasks_proxy)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(tasks_view)
|
||||
|
||||
selection_model = tasks_view.selectionModel()
|
||||
selection_model.selectionChanged.connect(self._on_task_change)
|
||||
|
||||
self._tasks_model = tasks_model
|
||||
self._tasks_proxy = tasks_proxy
|
||||
self._tasks_view = tasks_view
|
||||
|
||||
self._last_selected_task_name = None
|
||||
|
||||
def refresh(self):
|
||||
self._tasks_model.refresh()
|
||||
|
||||
def set_asset_id(self, asset_id):
|
||||
# Try and preserve the last selected task and reselect it
|
||||
# after switching assets. If there's no currently selected
|
||||
# asset keep whatever the "last selected" was prior to it.
|
||||
current = self.get_selected_task_name()
|
||||
if current:
|
||||
self._last_selected_task_name = current
|
||||
|
||||
self._tasks_model.set_asset_id(asset_id)
|
||||
|
||||
if self._last_selected_task_name:
|
||||
self.select_task_name(self._last_selected_task_name)
|
||||
|
||||
# Force a task changed emit.
|
||||
self.task_changed.emit()
|
||||
|
||||
def _clear_selection(self):
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
selection_model.clearSelection()
|
||||
|
||||
def select_task_name(self, task_name):
|
||||
"""Select a task by name.
|
||||
|
||||
If the task does not exist in the current model then selection is only
|
||||
cleared.
|
||||
|
||||
Args:
|
||||
task_name (str): Name of the task to select.
|
||||
|
||||
"""
|
||||
task_view_model = self._tasks_view.model()
|
||||
if not task_view_model:
|
||||
return
|
||||
|
||||
# Clear selection
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
selection_model.clearSelection()
|
||||
|
||||
# Select the task
|
||||
mode = (
|
||||
QtCore.QItemSelectionModel.Select
|
||||
| QtCore.QItemSelectionModel.Rows
|
||||
)
|
||||
for row in range(task_view_model.rowCount()):
|
||||
index = task_view_model.index(row, 0)
|
||||
name = index.data(TASK_NAME_ROLE)
|
||||
if name == task_name:
|
||||
selection_model.select(index, mode)
|
||||
|
||||
# Set the currently active index
|
||||
self._tasks_view.setCurrentIndex(index)
|
||||
break
|
||||
|
||||
last_selected_task_name = self.get_selected_task_name()
|
||||
if last_selected_task_name:
|
||||
self._last_selected_task_name = last_selected_task_name
|
||||
|
||||
if not self._enabled:
|
||||
current = self.get_selected_task_name()
|
||||
if current:
|
||||
self._last_selected_task_name = current
|
||||
self._clear_selection()
|
||||
|
||||
def get_selected_task_name(self):
|
||||
"""Return name of task at current index (selected)
|
||||
|
||||
Returns:
|
||||
str: Name of the current task.
|
||||
|
||||
"""
|
||||
index = self._tasks_view.currentIndex()
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
if index.isValid() and selection_model.isSelected(index):
|
||||
return index.data(TASK_NAME_ROLE)
|
||||
return None
|
||||
|
||||
def get_selected_task_type(self):
|
||||
index = self._tasks_view.currentIndex()
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
if index.isValid() and selection_model.isSelected(index):
|
||||
return index.data(TASK_TYPE_ROLE)
|
||||
return None
|
||||
|
||||
def set_asset_name(self, asset_name):
|
||||
current = self.get_selected_task_name()
|
||||
|
|
@ -163,14 +311,6 @@ class CreateWidgetTasksWidget(TasksWidget):
|
|||
# Force a task changed emit.
|
||||
self.task_changed.emit()
|
||||
|
||||
def select_task_name(self, task_name):
|
||||
super(CreateWidgetTasksWidget, self).select_task_name(task_name)
|
||||
if not self._enabled:
|
||||
current = self.get_selected_task_name()
|
||||
if current:
|
||||
self._last_selected_task_name = current
|
||||
self._clear_selection()
|
||||
|
||||
def set_enabled(self, enabled):
|
||||
self._enabled = enabled
|
||||
if not enabled:
|
||||
|
|
@ -181,3 +321,6 @@ class CreateWidgetTasksWidget(TasksWidget):
|
|||
|
||||
elif self._last_selected_task_name is not None:
|
||||
self.select_task_name(self._last_selected_task_name)
|
||||
|
||||
def _on_task_change(self):
|
||||
self.task_changed.emit()
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ from .models import SiteSyncModel
|
|||
class SceneInventoryController:
|
||||
"""This is a temporary controller for AYON.
|
||||
|
||||
Goal of this temporary controller is to provide a way to get current
|
||||
context instead of using 'AvalonMongoDB' object (or 'legacy_io').
|
||||
Goal of this controller is to provide a way to get current context.
|
||||
|
||||
Also provides (hopefully) cleaner api for site sync.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import speedcopy
|
|||
|
||||
from ayon_core.client import get_project, get_asset_by_name
|
||||
from ayon_core.lib import Terminal
|
||||
from ayon_core.pipeline import legacy_io, Anatomy
|
||||
from ayon_core.pipeline import Anatomy
|
||||
|
||||
|
||||
t = Terminal()
|
||||
|
|
@ -16,11 +16,6 @@ texture_extensions = ['.tif', '.tiff', '.jpg', '.jpeg', '.tx', '.png', '.tga',
|
|||
|
||||
|
||||
class TextureCopy:
|
||||
|
||||
def __init__(self):
|
||||
if not legacy_io.Session:
|
||||
legacy_io.install()
|
||||
|
||||
def _get_textures(self, path):
|
||||
textures = []
|
||||
for dir, subdir, files in os.walk(path):
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@ class _AssetModel(QtGui.QStandardItemModel):
|
|||
'refreshed' signal.
|
||||
|
||||
Args:
|
||||
dbcon (AvalonMongoDB): Ready to use connection to mongo with.
|
||||
parent (QObject): Parent Qt object.
|
||||
"""
|
||||
|
||||
|
|
@ -128,9 +127,8 @@ class _AssetModel(QtGui.QStandardItemModel):
|
|||
"data.color": 1
|
||||
}
|
||||
|
||||
def __init__(self, dbcon, parent=None):
|
||||
def __init__(self, parent=None):
|
||||
super(_AssetModel, self).__init__(parent=parent)
|
||||
self.dbcon = dbcon
|
||||
|
||||
self._refreshing = False
|
||||
self._doc_fetching_thread = None
|
||||
|
|
@ -142,6 +140,7 @@ class _AssetModel(QtGui.QStandardItemModel):
|
|||
self._item_ids_with_color = set()
|
||||
self._items_by_asset_id = {}
|
||||
|
||||
self._project_name = None
|
||||
self._last_project_name = None
|
||||
|
||||
@property
|
||||
|
|
@ -185,6 +184,16 @@ class _AssetModel(QtGui.QStandardItemModel):
|
|||
|
||||
return self.get_indexes_by_asset_ids(asset_ids)
|
||||
|
||||
def get_project_name(self):
|
||||
return self._project_name
|
||||
|
||||
def set_project_name(self, project_name, refresh):
|
||||
if self._project_name == project_name:
|
||||
return
|
||||
self._project_name = project_name
|
||||
if refresh:
|
||||
self.refresh()
|
||||
|
||||
def refresh(self, force=False):
|
||||
"""Refresh the data for the model.
|
||||
|
||||
|
|
@ -197,7 +206,7 @@ class _AssetModel(QtGui.QStandardItemModel):
|
|||
return
|
||||
self.stop_refresh()
|
||||
|
||||
project_name = self.dbcon.Session.get("AVALON_PROJECT")
|
||||
project_name = self._project_name
|
||||
clear_model = False
|
||||
if project_name != self._last_project_name:
|
||||
clear_model = True
|
||||
|
|
@ -216,23 +225,6 @@ class _AssetModel(QtGui.QStandardItemModel):
|
|||
def stop_refresh(self):
|
||||
self._stop_fetch_thread()
|
||||
|
||||
def clear_underlines(self):
|
||||
for asset_id in set(self._item_ids_with_color):
|
||||
self._item_ids_with_color.remove(asset_id)
|
||||
item = self._items_by_asset_id.get(asset_id)
|
||||
if item is not None:
|
||||
item.setData(None, ASSET_UNDERLINE_COLORS_ROLE)
|
||||
|
||||
def set_underline_colors(self, colors_by_asset_id):
|
||||
self.clear_underlines()
|
||||
|
||||
for asset_id, colors in colors_by_asset_id.items():
|
||||
item = self._items_by_asset_id.get(asset_id)
|
||||
if item is None:
|
||||
continue
|
||||
item.setData(colors, ASSET_UNDERLINE_COLORS_ROLE)
|
||||
self._item_ids_with_color.add(asset_id)
|
||||
|
||||
def _clear_items(self):
|
||||
root_item = self.invisibleRootItem()
|
||||
root_item.removeRows(0, root_item.rowCount())
|
||||
|
|
@ -357,7 +349,7 @@ class _AssetModel(QtGui.QStandardItemModel):
|
|||
self._doc_fetched.emit()
|
||||
|
||||
def _fetch_asset_docs(self):
|
||||
project_name = self.dbcon.current_project()
|
||||
project_name = self.get_project_name()
|
||||
if not project_name:
|
||||
return []
|
||||
|
||||
|
|
@ -392,7 +384,6 @@ class _AssetsWidget(QtWidgets.QWidget):
|
|||
inheritance changes.
|
||||
|
||||
Args:
|
||||
dbcon (AvalonMongoDB): Connection to avalon mongo db.
|
||||
parent (QWidget): Parent Qt widget.
|
||||
"""
|
||||
|
||||
|
|
@ -404,11 +395,9 @@ class _AssetsWidget(QtWidgets.QWidget):
|
|||
# It was double clicked on view
|
||||
double_clicked = QtCore.Signal()
|
||||
|
||||
def __init__(self, dbcon, parent=None):
|
||||
def __init__(self, parent=None):
|
||||
super(_AssetsWidget, self).__init__(parent=parent)
|
||||
|
||||
self.dbcon = dbcon
|
||||
|
||||
# Tree View
|
||||
model = self._create_source_model()
|
||||
proxy = self._create_proxy_model(model)
|
||||
|
|
@ -477,18 +466,28 @@ class _AssetsWidget(QtWidgets.QWidget):
|
|||
self._model = model
|
||||
self._proxy = proxy
|
||||
self._view = view
|
||||
self._last_project_name = None
|
||||
|
||||
self._last_btns_height = None
|
||||
|
||||
self._current_asset_name = None
|
||||
|
||||
self.model_selection = {}
|
||||
|
||||
@property
|
||||
def header_widget(self):
|
||||
return self._header_widget
|
||||
|
||||
def get_project_name(self):
|
||||
self._model.get_project_name()
|
||||
|
||||
def set_project_name(self, project_name, refresh=True):
|
||||
self._model.set_project_name(project_name, refresh)
|
||||
|
||||
def set_current_asset_name(self, asset_name):
|
||||
self._current_asset_name = asset_name
|
||||
|
||||
def _create_source_model(self):
|
||||
model = _AssetModel(dbcon=self.dbcon, parent=self)
|
||||
model = _AssetModel(parent=self)
|
||||
model.refreshed.connect(self._on_model_refresh)
|
||||
return model
|
||||
|
||||
|
|
@ -509,8 +508,8 @@ class _AssetsWidget(QtWidgets.QWidget):
|
|||
def stop_refresh(self):
|
||||
self._model.stop_refresh()
|
||||
|
||||
def _get_current_session_asset(self):
|
||||
return self.dbcon.Session.get("AVALON_ASSET")
|
||||
def _get_current_asset_name(self):
|
||||
return self._current_asset_name
|
||||
|
||||
def _on_current_asset_click(self):
|
||||
"""Trigger change of asset to current context asset.
|
||||
|
|
@ -518,10 +517,10 @@ class _AssetsWidget(QtWidgets.QWidget):
|
|||
in differnt way.
|
||||
"""
|
||||
|
||||
self.set_current_session_asset()
|
||||
self.select_current_asset()
|
||||
|
||||
def set_current_session_asset(self):
|
||||
asset_name = self._get_current_session_asset()
|
||||
def select_current_asset(self):
|
||||
asset_name = self._get_current_asset_name()
|
||||
if asset_name:
|
||||
self.select_asset_by_name(asset_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,303 +0,0 @@
|
|||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
import qtawesome
|
||||
|
||||
from ayon_core.client import (
|
||||
get_project,
|
||||
get_asset_by_id,
|
||||
)
|
||||
from ayon_core.style import get_disabled_entity_icon_color
|
||||
from ayon_core.tools.utils.lib import get_task_icon
|
||||
|
||||
from .views import DeselectableTreeView
|
||||
|
||||
|
||||
TASK_NAME_ROLE = QtCore.Qt.UserRole + 1
|
||||
TASK_TYPE_ROLE = QtCore.Qt.UserRole + 2
|
||||
TASK_ORDER_ROLE = QtCore.Qt.UserRole + 3
|
||||
TASK_ASSIGNEE_ROLE = QtCore.Qt.UserRole + 4
|
||||
|
||||
|
||||
class _TasksModel(QtGui.QStandardItemModel):
|
||||
"""A model listing the tasks combined for a list of assets"""
|
||||
|
||||
def __init__(self, dbcon, parent=None):
|
||||
super(_TasksModel, self).__init__(parent=parent)
|
||||
self.dbcon = dbcon
|
||||
self.setHeaderData(
|
||||
0, QtCore.Qt.Horizontal, "Tasks", QtCore.Qt.DisplayRole
|
||||
)
|
||||
|
||||
self._no_tasks_icon = qtawesome.icon(
|
||||
"fa.exclamation-circle",
|
||||
color=get_disabled_entity_icon_color()
|
||||
)
|
||||
self._cached_icons = {}
|
||||
self._project_doc = {}
|
||||
|
||||
self._empty_tasks_item = None
|
||||
self._last_asset_id = None
|
||||
self._loaded_project_name = None
|
||||
|
||||
def _context_is_valid(self):
|
||||
if self._get_current_project():
|
||||
return True
|
||||
return False
|
||||
|
||||
def refresh(self):
|
||||
self._refresh_project_doc()
|
||||
self.set_asset_id(self._last_asset_id)
|
||||
|
||||
def _refresh_project_doc(self):
|
||||
# Get the project configured icons from database
|
||||
project_doc = {}
|
||||
if self._context_is_valid():
|
||||
project_name = self.dbcon.active_project()
|
||||
project_doc = get_project(project_name)
|
||||
|
||||
self._loaded_project_name = self._get_current_project()
|
||||
self._project_doc = project_doc
|
||||
|
||||
def headerData(self, section, orientation, role=None):
|
||||
if role is None:
|
||||
role = QtCore.Qt.EditRole
|
||||
# Show nice labels in the header
|
||||
if section == 0:
|
||||
if (
|
||||
role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole)
|
||||
and orientation == QtCore.Qt.Horizontal
|
||||
):
|
||||
return "Tasks"
|
||||
|
||||
return super(_TasksModel, self).headerData(section, orientation, role)
|
||||
|
||||
def _get_current_project(self):
|
||||
return self.dbcon.Session.get("AVALON_PROJECT")
|
||||
|
||||
def set_asset_id(self, asset_id):
|
||||
asset_doc = None
|
||||
if asset_id and self._context_is_valid():
|
||||
project_name = self._get_current_project()
|
||||
asset_doc = get_asset_by_id(
|
||||
project_name, asset_id, fields=["data.tasks"]
|
||||
)
|
||||
self._set_asset(asset_doc)
|
||||
|
||||
def _get_empty_task_item(self):
|
||||
if self._empty_tasks_item is None:
|
||||
item = QtGui.QStandardItem("No task")
|
||||
item.setData(self._no_tasks_icon, QtCore.Qt.DecorationRole)
|
||||
item.setFlags(QtCore.Qt.NoItemFlags)
|
||||
self._empty_tasks_item = item
|
||||
return self._empty_tasks_item
|
||||
|
||||
def _set_asset(self, asset_doc):
|
||||
"""Set assets to track by their database id
|
||||
|
||||
Arguments:
|
||||
asset_doc (dict): Asset document from MongoDB.
|
||||
"""
|
||||
if self._loaded_project_name != self._get_current_project():
|
||||
self._refresh_project_doc()
|
||||
|
||||
asset_tasks = {}
|
||||
self._last_asset_id = None
|
||||
if asset_doc:
|
||||
asset_tasks = asset_doc.get("data", {}).get("tasks") or {}
|
||||
self._last_asset_id = asset_doc["_id"]
|
||||
|
||||
root_item = self.invisibleRootItem()
|
||||
root_item.removeRows(0, root_item.rowCount())
|
||||
|
||||
items = []
|
||||
|
||||
for task_name, task_info in asset_tasks.items():
|
||||
task_type = task_info.get("type")
|
||||
task_order = task_info.get("order")
|
||||
icon = get_task_icon(self._project_doc, asset_doc, task_name)
|
||||
|
||||
task_assignees = set()
|
||||
assignees_data = task_info.get("assignees") or []
|
||||
for assignee in assignees_data:
|
||||
username = assignee.get("username")
|
||||
if username:
|
||||
task_assignees.add(username)
|
||||
|
||||
label = "{} ({})".format(task_name, task_type or "type N/A")
|
||||
item = QtGui.QStandardItem(label)
|
||||
item.setData(task_name, TASK_NAME_ROLE)
|
||||
item.setData(task_type, TASK_TYPE_ROLE)
|
||||
item.setData(task_order, TASK_ORDER_ROLE)
|
||||
item.setData(task_assignees, TASK_ASSIGNEE_ROLE)
|
||||
item.setData(icon, QtCore.Qt.DecorationRole)
|
||||
item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
|
||||
items.append(item)
|
||||
|
||||
if not items:
|
||||
item = QtGui.QStandardItem("No task")
|
||||
item.setData(self._no_tasks_icon, QtCore.Qt.DecorationRole)
|
||||
item.setFlags(QtCore.Qt.NoItemFlags)
|
||||
items.append(item)
|
||||
|
||||
root_item.appendRows(items)
|
||||
|
||||
|
||||
class _TasksProxyModel(QtCore.QSortFilterProxyModel):
|
||||
def lessThan(self, x_index, y_index):
|
||||
x_order = x_index.data(TASK_ORDER_ROLE)
|
||||
y_order = y_index.data(TASK_ORDER_ROLE)
|
||||
if x_order is not None and y_order is not None:
|
||||
if x_order < y_order:
|
||||
return True
|
||||
if x_order > y_order:
|
||||
return False
|
||||
|
||||
elif x_order is None and y_order is not None:
|
||||
return True
|
||||
|
||||
elif y_order is None and x_order is not None:
|
||||
return False
|
||||
|
||||
x_name = x_index.data(QtCore.Qt.DisplayRole)
|
||||
y_name = y_index.data(QtCore.Qt.DisplayRole)
|
||||
if x_name == y_name:
|
||||
return True
|
||||
|
||||
if x_name == tuple(sorted((x_name, y_name)))[0]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class TasksWidget(QtWidgets.QWidget):
|
||||
"""Widget showing active Tasks
|
||||
|
||||
Deprecated:
|
||||
This widget will be removed soon. Please do not use it in new code.
|
||||
"""
|
||||
|
||||
task_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, dbcon, parent=None):
|
||||
self._dbcon = dbcon
|
||||
|
||||
super(TasksWidget, self).__init__(parent)
|
||||
|
||||
tasks_view = DeselectableTreeView(self)
|
||||
tasks_view.setIndentation(0)
|
||||
tasks_view.setSortingEnabled(True)
|
||||
tasks_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
|
||||
header_view = tasks_view.header()
|
||||
header_view.setSortIndicator(0, QtCore.Qt.AscendingOrder)
|
||||
|
||||
tasks_model = self._create_source_model()
|
||||
tasks_proxy = self._create_proxy_model(tasks_model)
|
||||
tasks_view.setModel(tasks_proxy)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(tasks_view)
|
||||
|
||||
selection_model = tasks_view.selectionModel()
|
||||
selection_model.selectionChanged.connect(self._on_task_change)
|
||||
|
||||
self._tasks_model = tasks_model
|
||||
self._tasks_proxy = tasks_proxy
|
||||
self._tasks_view = tasks_view
|
||||
|
||||
self._last_selected_task_name = None
|
||||
|
||||
def _create_source_model(self):
|
||||
"""Create source model of tasks widget.
|
||||
|
||||
Model must have available 'refresh' method and 'set_asset_id' to change
|
||||
context of asset.
|
||||
"""
|
||||
return _TasksModel(self._dbcon)
|
||||
|
||||
def _create_proxy_model(self, source_model):
|
||||
proxy = _TasksProxyModel()
|
||||
proxy.setSourceModel(source_model)
|
||||
return proxy
|
||||
|
||||
def refresh(self):
|
||||
self._tasks_model.refresh()
|
||||
|
||||
def set_asset_id(self, asset_id):
|
||||
# Try and preserve the last selected task and reselect it
|
||||
# after switching assets. If there's no currently selected
|
||||
# asset keep whatever the "last selected" was prior to it.
|
||||
current = self.get_selected_task_name()
|
||||
if current:
|
||||
self._last_selected_task_name = current
|
||||
|
||||
self._tasks_model.set_asset_id(asset_id)
|
||||
|
||||
if self._last_selected_task_name:
|
||||
self.select_task_name(self._last_selected_task_name)
|
||||
|
||||
# Force a task changed emit.
|
||||
self.task_changed.emit()
|
||||
|
||||
def _clear_selection(self):
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
selection_model.clearSelection()
|
||||
|
||||
def select_task_name(self, task_name):
|
||||
"""Select a task by name.
|
||||
|
||||
If the task does not exist in the current model then selection is only
|
||||
cleared.
|
||||
|
||||
Args:
|
||||
task (str): Name of the task to select.
|
||||
|
||||
"""
|
||||
task_view_model = self._tasks_view.model()
|
||||
if not task_view_model:
|
||||
return
|
||||
|
||||
# Clear selection
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
selection_model.clearSelection()
|
||||
|
||||
# Select the task
|
||||
mode = (
|
||||
QtCore.QItemSelectionModel.Select
|
||||
| QtCore.QItemSelectionModel.Rows
|
||||
)
|
||||
for row in range(task_view_model.rowCount()):
|
||||
index = task_view_model.index(row, 0)
|
||||
name = index.data(TASK_NAME_ROLE)
|
||||
if name == task_name:
|
||||
selection_model.select(index, mode)
|
||||
|
||||
# Set the currently active index
|
||||
self._tasks_view.setCurrentIndex(index)
|
||||
break
|
||||
|
||||
last_selected_task_name = self.get_selected_task_name()
|
||||
if last_selected_task_name:
|
||||
self._last_selected_task_name = last_selected_task_name
|
||||
|
||||
def get_selected_task_name(self):
|
||||
"""Return name of task at current index (selected)
|
||||
|
||||
Returns:
|
||||
str: Name of the current task.
|
||||
|
||||
"""
|
||||
index = self._tasks_view.currentIndex()
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
if index.isValid() and selection_model.isSelected(index):
|
||||
return index.data(TASK_NAME_ROLE)
|
||||
return None
|
||||
|
||||
def get_selected_task_type(self):
|
||||
index = self._tasks_view.currentIndex()
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
if index.isValid() and selection_model.isSelected(index):
|
||||
return index.data(TASK_TYPE_ROLE)
|
||||
return None
|
||||
|
||||
def _on_task_change(self):
|
||||
self.task_changed.emit()
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
from .window import WorkfileBuildPlaceholderDialog
|
||||
from .lib import open_template_ui
|
||||
|
||||
__all__ = (
|
||||
"WorkfileBuildPlaceholderDialog",
|
||||
|
||||
"open_template_ui"
|
||||
)
|
||||
|
|
|
|||
28
client/ayon_core/tools/workfile_template_build/lib.py
Normal file
28
client/ayon_core/tools/workfile_template_build/lib.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import traceback
|
||||
|
||||
from qtpy import QtWidgets
|
||||
|
||||
from ayon_core.tools.utils.dialogs import show_message_dialog
|
||||
|
||||
|
||||
def open_template_ui(builder, main_window):
|
||||
"""Open template from `builder`
|
||||
|
||||
Asks user about overwriting current scene and feedsback exceptions.
|
||||
"""
|
||||
result = QtWidgets.QMessageBox.question(
|
||||
main_window,
|
||||
"Opening template",
|
||||
"Caution! You will loose unsaved changes.\nDo you want to continue?",
|
||||
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||
)
|
||||
if result == QtWidgets.QMessageBox.Yes:
|
||||
try:
|
||||
builder.open_template()
|
||||
except Exception:
|
||||
show_message_dialog(
|
||||
title="Template Load Failed",
|
||||
message="".join(traceback.format_exc()),
|
||||
parent=main_window,
|
||||
level="critical"
|
||||
)
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
import os
|
||||
|
||||
from qtpy import QtWidgets
|
||||
|
||||
from ayon_core import style
|
||||
from ayon_core.lib import Logger
|
||||
from ayon_core.pipeline import legacy_io
|
||||
from ayon_core.tools.attribute_defs import AttributeDefinitionsWidget
|
||||
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ class WorkfileBuildPlaceholderDialog(QtWidgets.QDialog):
|
|||
|
||||
host_name = getattr(self._host, "name", None)
|
||||
if not host_name:
|
||||
host_name = legacy_io.Session.get("AVALON_APP") or "NA"
|
||||
host_name = os.getenv("AVALON_APP") or "NA"
|
||||
self._host_name = host_name
|
||||
|
||||
plugins_combo = QtWidgets.QComboBox(self)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ wsrpc_aiohttp = "^3.1.1" # websocket server
|
|||
Click = "^8"
|
||||
clique = "1.6.*"
|
||||
jsonschema = "^2.6.0"
|
||||
pymongo = "^3.11.2"
|
||||
log4mongo = "^1.7"
|
||||
pyblish-base = "^1.8.11"
|
||||
pynput = "^1.7.2" # Timers manager - TODO remove
|
||||
speedcopy = "^2.1"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue