Merge branch 'develop' of github.com:pypeclub/OpenPype into chore/OP-3113_SAP-ExtractBGMainGroups

This commit is contained in:
Petr Kalis 2022-05-06 13:24:50 +02:00
commit 063392054a
24 changed files with 478 additions and 644 deletions

View file

@ -266,7 +266,7 @@ class AssetLoader(LoaderPlugin):
# Only containerise if it's not already a collection from a .blend file.
# representation = context["representation"]["name"]
# if representation != "blend":
# from avalon.blender.pipeline import containerise
# from openpype.hosts.blender.api.pipeline import containerise
# return containerise(
# name=name,
# namespace=namespace,

View file

@ -45,7 +45,8 @@ def install():
This is where you install menus and register families, data
and loaders into fusion.
It is called automatically when installing via `api.install(avalon.fusion)`
It is called automatically when installing via
`openpype.pipeline.install_host(openpype.hosts.fusion.api)`
See the Maya equivalent for inspiration on how to implement this.

View file

@ -463,7 +463,7 @@ def imprint(node_id, data, remove=False):
remove (bool): Removes the data from the scene.
Example:
>>> from avalon.harmony import lib
>>> from openpype.hosts.harmony.api import lib
>>> node = "Top/Display"
>>> data = {"str": "someting", "int": 1, "float": 0.32, "bool": True}
>>> lib.imprint(layer, data)

View file

@ -553,10 +553,10 @@ class PublishAction(QtWidgets.QAction):
#
# '''
# import hiero.core
# from avalon.nuke import imprint
# from pype.hosts.nuke import (
# lib as nklib
# )
# from openpype.hosts.nuke.api.lib import (
# BuildWorkfile,
# imprint
# )
#
# # check if the file exists if does then Raise "File exists!"
# if os.path.exists(filepath):
@ -583,8 +583,7 @@ class PublishAction(QtWidgets.QAction):
#
# nuke_script.addNode(root_node)
#
# # here to call pype.hosts.nuke.lib.BuildWorkfile
# script_builder = nklib.BuildWorkfile(
# script_builder = BuildWorkfile(
# root_node=root_node,
# root_path=root_path,
# nodes=nuke_script.getNodes(),

View file

@ -0,0 +1,75 @@
import os
from openpype.pipeline import (
load,
get_representation_path,
)
from openpype.hosts.houdini.api import pipeline
class AbcArchiveLoader(load.LoaderPlugin):
"""Load Alembic as full geometry network hierarchy """
families = ["model", "animation", "pointcache", "gpuCache"]
label = "Load Alembic as Archive"
representations = ["abc"]
order = -5
icon = "code-fork"
color = "orange"
def load(self, context, name=None, namespace=None, data=None):
import hou
# Format file name, Houdini only wants forward slashes
file_path = os.path.normpath(self.fname)
file_path = file_path.replace("\\", "/")
# Get the root node
obj = hou.node("/obj")
# Define node name
namespace = namespace if namespace else context["asset"]["name"]
node_name = "{}_{}".format(namespace, name) if namespace else name
# Create an Alembic archive node
node = obj.createNode("alembicarchive", node_name=node_name)
node.moveToGoodPosition()
# TODO: add FPS of project / asset
node.setParms({"fileName": file_path,
"channelRef": True})
# Apply some magic
node.parm("buildHierarchy").pressButton()
node.moveToGoodPosition()
nodes = [node]
self[:] = nodes
return pipeline.containerise(node_name,
namespace,
nodes,
context,
self.__class__.__name__,
suffix="")
def update(self, container, representation):
node = container["node"]
# Update the file path
file_path = get_representation_path(representation)
file_path = file_path.replace("\\", "/")
# Update attributes
node.setParms({"fileName": file_path,
"representation": str(representation["_id"])})
# Rebuild
node.parm("buildHierarchy").pressButton()
def remove(self, container):
node = container["node"]
node.destroy()

View file

@ -1,3 +1,7 @@
import os
import subprocess
from openpype.lib.vendor_bin_utils import find_executable
from openpype.pipeline import load
@ -14,12 +18,7 @@ class ShowInUsdview(load.LoaderPlugin):
def load(self, context, name=None, namespace=None, data=None):
import os
import subprocess
import avalon.lib as lib
usdview = lib.which("usdview")
usdview = find_executable("usdview")
filepath = os.path.normpath(self.fname)
filepath = filepath.replace("\\", "/")

View file

@ -2,7 +2,7 @@ import openpype.hosts.maya.api.plugin
class AbcLoader(openpype.hosts.maya.api.plugin.ReferenceLoader):
"""Specific loader of Alembic for the avalon.animation family"""
"""Loader to reference an Alembic file"""
families = ["animation",
"camera",

View file

@ -193,7 +193,7 @@ def imprint(node, data, tab=None):
Examples:
```
import nuke
from avalon.nuke import lib
from openpype.hosts.nuke.api import lib
node = nuke.createNode("NoOp")
data = {
@ -858,6 +858,7 @@ def create_write_node(name, data, input=None, prenodes=None,
Return:
node (obj): group node with avalon data as Knobs
'''
knob_overrides = data.get("knobs", [])
imageio_writes = get_created_node_imageio_setting(**data)
for knob in imageio_writes["knobs"]:
@ -1061,6 +1062,30 @@ def create_write_node(name, data, input=None, prenodes=None,
tile_color = _data.get("tile_color", "0xff0000ff")
GN["tile_color"].setValue(tile_color)
# overrie knob values from settings
for knob in knob_overrides:
knob_type = knob["type"]
knob_name = knob["name"]
knob_value = knob["value"]
if knob_name not in GN.knobs():
continue
if not knob_value:
continue
# set correctly knob types
if knob_type == "string":
knob_value = str(knob_value)
if knob_type == "number":
knob_value = int(knob_value)
if knob_type == "decimal_number":
knob_value = float(knob_value)
if knob_type == "bool":
knob_value = bool(knob_value)
if knob_type in ["2d_vector", "3d_vector"]:
knob_value = list(knob_value)
GN[knob_name].setValue(knob_value)
return GN

View file

@ -605,6 +605,7 @@ class AbstractWriteRender(OpenPypeCreator):
family = "render"
icon = "sign-out"
defaults = ["Main", "Mask"]
knobs = []
def __init__(self, *args, **kwargs):
super(AbstractWriteRender, self).__init__(*args, **kwargs)
@ -672,7 +673,8 @@ class AbstractWriteRender(OpenPypeCreator):
"nodeclass": self.n_class,
"families": [self.family],
"avalon": self.data,
"subset": self.data["subset"]
"subset": self.data["subset"],
"knobs": self.knobs
}
# add creator data

View file

@ -13,6 +13,7 @@ class CreateWriteRender(plugin.AbstractWriteRender):
family = "render"
icon = "sign-out"
defaults = ["Main", "Mask"]
knobs = []
def __init__(self, *args, **kwargs):
super(CreateWriteRender, self).__init__(*args, **kwargs)
@ -38,13 +39,12 @@ class CreateWriteRender(plugin.AbstractWriteRender):
}
]
write_node = create_write_node(
return create_write_node(
self.data["subset"],
write_data,
input=selected_node,
prenodes=_prenodes)
return write_node
prenodes=_prenodes
)
def _modify_write_node(self, write_node):
return write_node

View file

@ -573,7 +573,7 @@ def composite_rendered_layers(
layer_ids_by_position[layer_position] = layer["layer_id"]
# Sort layer positions
sorted_positions = tuple(sorted(layer_ids_by_position.keys()))
sorted_positions = tuple(reversed(sorted(layer_ids_by_position.keys())))
# Prepare variable where filepaths without any rendered content
# - transparent will be created
transparent_filepaths = set()

View file

@ -1012,8 +1012,8 @@ class ApplicationLaunchContext:
self.log.debug("Discovery of launch hooks started.")
paths = self.paths_to_launch_hooks()
self.log.debug("Paths where will look for launch hooks:{}".format(
"\n- ".join(paths)
self.log.debug("Paths searched for launch hooks:\n{}".format(
"\n".join("- {}".format(path) for path in paths)
))
all_classes = {
@ -1023,7 +1023,7 @@ class ApplicationLaunchContext:
for path in paths:
if not os.path.exists(path):
self.log.info(
"Path to launch hooks does not exists: \"{}\"".format(path)
"Path to launch hooks does not exist: \"{}\"".format(path)
)
continue
@ -1044,13 +1044,14 @@ class ApplicationLaunchContext:
hook = klass(self)
if not hook.is_valid:
self.log.debug(
"Hook is not valid for current launch context."
"Skipped hook invalid for current launch context: "
"{}".format(klass.__name__)
)
continue
if inspect.isabstract(hook):
self.log.debug("Skipped abstract hook: {}".format(
str(hook)
klass.__name__
))
continue
@ -1062,7 +1063,8 @@ class ApplicationLaunchContext:
except Exception:
self.log.warning(
"Initialization of hook failed. {}".format(str(klass)),
"Initialization of hook failed: "
"{}".format(klass.__name__),
exc_info=True
)

View file

@ -98,7 +98,7 @@ class Terminal:
r"\*\*\* WRN": _SB + _LY + r"*** WRN" + _RST,
r" \- ": _SB + _LY + r" - " + _RST,
r"\[ ": _SB + _LG + r"[ " + _RST,
r"\]": _SB + _LG + r"]" + _RST,
r" \]": _SB + _LG + r" ]" + _RST,
r"{": _LG + r"{",
r"}": r"}" + _RST,
r"\(": _LY + r"(",

View file

@ -290,49 +290,16 @@ def _load_modules():
log = PypeLogger.get_logger("ModulesLoader")
current_dir = os.path.abspath(os.path.dirname(__file__))
processed_paths = set()
processed_paths.add(current_dir)
# Import default modules imported from 'openpype.modules'
for filename in os.listdir(current_dir):
# Ignore filenames
if (
filename in IGNORED_FILENAMES
or filename in IGNORED_DEFAULT_FILENAMES
):
continue
fullpath = os.path.join(current_dir, filename)
basename, ext = os.path.splitext(filename)
if os.path.isdir(fullpath):
# Check existence of init fil
init_path = os.path.join(fullpath, "__init__.py")
if not os.path.exists(init_path):
log.debug((
"Module directory does not contan __init__.py file {}"
).format(fullpath))
continue
elif ext not in (".py", ):
continue
try:
import_str = "openpype.modules.{}".format(basename)
new_import_str = "{}.{}".format(modules_key, basename)
default_module = __import__(import_str, fromlist=("", ))
sys.modules[new_import_str] = default_module
setattr(openpype_modules, basename, default_module)
except Exception:
msg = (
"Failed to import default module '{}'."
).format(basename)
log.error(msg, exc_info=True)
# Look for OpenPype modules in paths defined with `get_module_dirs`
# - dynamically imported OpenPype modules and addons
for dirpath in get_module_dirs():
module_dirs = get_module_dirs()
# Add current directory at first place
# - has small differences in import logic
current_dir = os.path.abspath(os.path.dirname(__file__))
module_dirs.insert(0, current_dir)
processed_paths = set()
for dirpath in module_dirs:
# Skip already processed paths
if dirpath in processed_paths:
continue
@ -344,20 +311,29 @@ def _load_modules():
).format(dirpath))
continue
is_in_current_dir = dirpath == current_dir
for filename in os.listdir(dirpath):
# Ignore filenames
if filename in IGNORED_FILENAMES:
continue
if (
is_in_current_dir
and filename in IGNORED_DEFAULT_FILENAMES
):
continue
fullpath = os.path.join(dirpath, filename)
basename, ext = os.path.splitext(filename)
# Validations
if os.path.isdir(fullpath):
# Check existence of init fil
# Check existence of init file
init_path = os.path.join(fullpath, "__init__.py")
if not os.path.exists(init_path):
log.debug((
"Module directory does not contan __init__.py file {}"
"Module directory does not contain __init__.py"
" file {}"
).format(fullpath))
continue
@ -367,27 +343,29 @@ def _load_modules():
# TODO add more logic how to define if folder is module or not
# - check manifest and content of manifest
try:
if os.path.isdir(fullpath):
# Module without init file can't be used as OpenPype module
# because the module class could not be imported
init_file = os.path.join(fullpath, "__init__.py")
if not os.path.exists(init_file):
log.info((
"Skipping module directory because of"
" missing \"__init__.py\" file. \"{}\""
).format(fullpath))
continue
# Don't import dynamically current directory modules
if is_in_current_dir:
import_str = "openpype.modules.{}".format(basename)
new_import_str = "{}.{}".format(modules_key, basename)
default_module = __import__(import_str, fromlist=("", ))
sys.modules[new_import_str] = default_module
setattr(openpype_modules, basename, default_module)
elif os.path.isdir(fullpath):
import_module_from_dirpath(dirpath, filename, modules_key)
elif ext in (".py", ):
else:
module = import_filepath(fullpath)
setattr(openpype_modules, basename, module)
except Exception:
log.error(
"Failed to import '{}'.".format(fullpath),
exc_info=True
)
if is_in_current_dir:
msg = "Failed to import default module '{}'.".format(
basename
)
else:
msg = "Failed to import module '{}'.".format(fullpath)
log.error(msg, exc_info=True)
class _OpenPypeInterfaceMeta(ABCMeta):

View file

@ -25,7 +25,7 @@ def install():
session = session_data_from_environment(context_keys=True)
session["schema"] = "openpype:session-2.0"
session["schema"] = "openpype:session-3.0"
try:
schema.validate(session)
except schema.ValidationError as e:

View file

@ -170,7 +170,7 @@
"regexInputs": {
"inputs": [
{
"regex": "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]",
"regex": "(beauty).*(?=.exr)",
"colorspace": "linear"
}
]

View file

@ -21,7 +21,8 @@
"defaults": [
"Main",
"Mask"
]
],
"knobs": []
},
"CreateWritePrerender": {
"fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}",
@ -33,7 +34,8 @@
"Branch01",
"Part01"
],
"reviewable": false
"reviewable": false,
"knobs": []
}
},
"publish": {
@ -220,11 +222,12 @@
"repre_names": [
"exr",
"dpx",
"mov"
"mov",
"mp4",
"h264"
],
"loaders": [
"LoadSequence",
"LoadMov"
"LoadClip"
]
}
],

View file

@ -87,7 +87,7 @@
"children": [
{
"type": "dict",
"collapsible": false,
"collapsible": true,
"key": "CreateWriteRender",
"label": "CreateWriteRender",
"is_group": true,
@ -104,12 +104,16 @@
"object_type": {
"type": "text"
}
},
{
"type": "schema",
"name": "schema_nuke_knob_inputs"
}
]
},
{
"type": "dict",
"collapsible": false,
"collapsible": true,
"key": "CreateWritePrerender",
"label": "CreateWritePrerender",
"is_group": true,
@ -136,6 +140,10 @@
"type": "boolean",
"key": "reviewable",
"label": "Add reviewable toggle"
},
{
"type": "schema",
"name": "schema_nuke_knob_inputs"
}
]
}

View file

@ -0,0 +1,151 @@
{
"type": "collapsible-wrap",
"label": "Knob defaults",
"collapsible": true,
"collapsed": true,
"children": [{
"type": "list",
"key": "knobs",
"object_type": {
"type": "dict-conditional",
"enum_key": "type",
"enum_label": "Type",
"enum_children": [
{
"key": "string",
"label": "String",
"children": [
{
"type": "text",
"key": "name",
"label": "Name"
},
{
"type": "text",
"key": "value",
"label": "Value"
}
]
},
{
"key": "bool",
"label": "Boolean",
"children": [
{
"type": "text",
"key": "name",
"label": "Name"
},
{
"type": "boolean",
"key": "value",
"label": "Value"
}
]
},
{
"key": "number",
"label": "Number",
"children": [
{
"type": "text",
"key": "name",
"label": "Name"
},
{
"type": "number",
"key": "value",
"default": 1,
"decimal": 0
}
]
},
{
"key": "decimal_number",
"label": "Decimal number",
"children": [
{
"type": "text",
"key": "name",
"label": "Name"
},
{
"type": "number",
"key": "value",
"default": 1,
"decimal": 4
}
]
},
{
"key": "2d_vector",
"label": "2D vector",
"children": [
{
"type": "text",
"key": "name",
"label": "Name"
},
{
"type": "list-strict",
"key": "value",
"label": "Value",
"object_types": [
{
"type": "number",
"key": "x",
"default": 1,
"decimal": 4
},
{
"type": "number",
"key": "y",
"default": 1,
"decimal": 4
}
]
}
]
},
{
"key": "3d_vector",
"label": "3D vector",
"children": [
{
"type": "text",
"key": "name",
"label": "Name"
},
{
"type": "list-strict",
"key": "value",
"label": "Value",
"object_types": [
{
"type": "number",
"key": "x",
"default": 1,
"decimal": 4
},
{
"type": "number",
"key": "y",
"default": 1,
"decimal": 4
},
{
"type": "number",
"key": "y",
"default": 1,
"decimal": 4
}
]
}
]
}
]
}
}]
}

View file

@ -1,494 +0,0 @@
import os
import getpass
import platform
from Qt import QtCore, QtGui, QtWidgets
from avalon import style
import ftrack_api
class Project_name_getUI(QtWidgets.QWidget):
'''
Project setting ui: here all the neceserry ui widgets are created
they are going to be used i later proces for dynamic linking of project
in list to project's attributes
'''
def __init__(self, parent=None):
super(Project_name_getUI, self).__init__(parent)
self.platform = platform.system()
self.new_index = 0
# get projects from ftrack
self.session = ftrack_api.Session()
self.projects_from_ft = self.session.query(
'Project where status is active')
self.disks_from_ft = self.session.query('Disk')
self.schemas_from_ft = self.session.query('ProjectSchema')
self.projects = self._get_projects_ftrack()
# define window geometry
self.setWindowTitle('Set project attributes')
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.resize(550, 340)
self.setStyleSheet(style.load_stylesheet())
# define disk combobox widget
self.disks = self._get_all_disks()
self.disk_combobox_label = QtWidgets.QLabel('Destination storage:')
self.disk_combobox = QtWidgets.QComboBox()
# define schema combobox widget
self.schemas = self._get_all_schemas()
self.schema_combobox_label = QtWidgets.QLabel('Project schema:')
self.schema_combobox = QtWidgets.QComboBox()
# define fps widget
self.fps_label = QtWidgets.QLabel('Fps:')
self.fps_label.setAlignment(
QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.fps = QtWidgets.QLineEdit()
# define project dir widget
self.project_dir_label = QtWidgets.QLabel('Project dir:')
self.project_dir_label.setAlignment(
QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.project_dir = QtWidgets.QLineEdit()
self.project_path_label = QtWidgets.QLabel(
'Project_path (if not then created):')
self.project_path_label.setAlignment(
QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
project_path_font = QtGui.QFont(
"Helvetica [Cronyx]", 12, QtGui.QFont.Bold)
self.project_path = QtWidgets.QLabel()
self.project_path.setObjectName('nom_plan_label')
self.project_path.setStyleSheet(
'QtWidgets.QLabel#nom_plan_label {color: red}')
self.project_path.setAlignment(
QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
self.project_path.setFont(project_path_font)
# define handles widget
self.handles_label = QtWidgets.QLabel('Handles:')
self.handles_label.setAlignment(
QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.handles = QtWidgets.QLineEdit()
# define resolution widget
self.resolution_w_label = QtWidgets.QLabel('W:')
self.resolution_w = QtWidgets.QLineEdit()
self.resolution_h_label = QtWidgets.QLabel('H:')
self.resolution_h = QtWidgets.QLineEdit()
devider = QtWidgets.QFrame()
# devider.Shape(QFrame.HLine)
devider.setFrameShape(QtWidgets.QFrame.HLine)
devider.setFrameShadow(QtWidgets.QFrame.Sunken)
self.generate_lines()
# define push buttons
self.set_pushbutton = QtWidgets.QPushButton('Set project')
self.cancel_pushbutton = QtWidgets.QPushButton('Cancel')
# definition of layouts
############################################
action_layout = QtWidgets.QHBoxLayout()
action_layout.addWidget(self.set_pushbutton)
action_layout.addWidget(self.cancel_pushbutton)
# schema property
schema_layout = QtWidgets.QGridLayout()
schema_layout.addWidget(self.schema_combobox, 0, 1)
schema_layout.addWidget(self.schema_combobox_label, 0, 0)
# storage property
storage_layout = QtWidgets.QGridLayout()
storage_layout.addWidget(self.disk_combobox, 0, 1)
storage_layout.addWidget(self.disk_combobox_label, 0, 0)
# fps property
fps_layout = QtWidgets.QGridLayout()
fps_layout.addWidget(self.fps, 1, 1)
fps_layout.addWidget(self.fps_label, 1, 0)
# project dir property
project_dir_layout = QtWidgets.QGridLayout()
project_dir_layout.addWidget(self.project_dir, 1, 1)
project_dir_layout.addWidget(self.project_dir_label, 1, 0)
# project path property
project_path_layout = QtWidgets.QGridLayout()
spacer_1_item = QtWidgets.QSpacerItem(10, 10)
project_path_layout.addItem(spacer_1_item, 0, 1)
project_path_layout.addWidget(self.project_path_label, 1, 1)
project_path_layout.addWidget(self.project_path, 2, 1)
spacer_2_item = QtWidgets.QSpacerItem(20, 20)
project_path_layout.addItem(spacer_2_item, 3, 1)
# handles property
handles_layout = QtWidgets.QGridLayout()
handles_layout.addWidget(self.handles, 1, 1)
handles_layout.addWidget(self.handles_label, 1, 0)
# resolution property
resolution_layout = QtWidgets.QGridLayout()
resolution_layout.addWidget(self.resolution_w_label, 1, 1)
resolution_layout.addWidget(self.resolution_w, 2, 1)
resolution_layout.addWidget(self.resolution_h_label, 1, 2)
resolution_layout.addWidget(self.resolution_h, 2, 2)
# form project property layout
p_layout = QtWidgets.QGridLayout()
p_layout.addLayout(storage_layout, 1, 0)
p_layout.addLayout(schema_layout, 2, 0)
p_layout.addLayout(project_dir_layout, 3, 0)
p_layout.addLayout(fps_layout, 4, 0)
p_layout.addLayout(handles_layout, 5, 0)
p_layout.addLayout(resolution_layout, 6, 0)
p_layout.addWidget(devider, 7, 0)
spacer_item = QtWidgets.QSpacerItem(
150,
40,
QtWidgets.QSizePolicy.Minimum,
QtWidgets.QSizePolicy.Expanding
)
p_layout.addItem(spacer_item, 8, 0)
# form with list to one layout with project property
list_layout = QtWidgets.QGridLayout()
list_layout.addLayout(p_layout, 1, 0)
list_layout.addWidget(self.listWidget, 1, 1)
root_layout = QtWidgets.QVBoxLayout()
root_layout.addLayout(project_path_layout)
root_layout.addWidget(devider)
root_layout.addLayout(list_layout)
root_layout.addLayout(action_layout)
self.setLayout(root_layout)
def generate_lines(self):
'''
Will generate lines of project list
'''
self.listWidget = QtWidgets.QListWidget()
for self.index, p in enumerate(self.projects):
item = QtWidgets.QListWidgetItem("{full_name}".format(**p))
# item.setSelected(False)
self.listWidget.addItem(item)
print(self.listWidget.indexFromItem(item))
# self.listWidget.setCurrentItem(self.listWidget.itemFromIndex(1))
# add options to schemas widget
self.schema_combobox.addItems(self.schemas)
# add options to disk widget
self.disk_combobox.addItems(self.disks)
# populate content of project info widgets
self.projects[1] = self._fill_project_attributes_widgets(p, None)
def _fill_project_attributes_widgets(self, p=None, index=None):
'''
will generate actual informations wich are saved on ftrack
'''
if index is None:
self.new_index = 1
if not p:
pass
# change schema selection
for i, schema in enumerate(self.schemas):
if p['project_schema']['name'] in schema:
break
self.schema_combobox.setCurrentIndex(i)
disk_name, disk_path = self._build_disk_path()
for i, disk in enumerate(self.disks):
if disk_name in disk:
break
# change disk selection
self.disk_combobox.setCurrentIndex(i)
# change project_dir selection
if "{root}".format(**p):
self.project_dir.setPlaceholderText("{root}".format(**p))
else:
print("not root so it was replaced with name")
self.project_dir.setPlaceholderText("{name}".format(**p))
p['root'] = p['name']
# set project path to show where it will be created
self.project_path.setText(
os.path.join(self.disks[i].split(' ')[-1],
self.project_dir.text()))
# change fps selection
self.fps.setPlaceholderText("{custom_attributes[fps]}".format(**p))
# change handles selection
self.handles.setPlaceholderText(
"{custom_attributes[handles]}".format(**p))
# change resolution selection
self.resolution_w.setPlaceholderText(
"{custom_attributes[resolution_width]}".format(**p))
self.resolution_h.setPlaceholderText(
"{custom_attributes[resolution_height]}".format(**p))
self.update_disk()
return p
def fix_project_path_literals(self, dir):
return dir.replace(' ', '_').lower()
def update_disk(self):
disk = self.disk_combobox.currentText().split(' ')[-1]
dir = self.project_dir.text()
if not dir:
dir = "{root}".format(**self.projects[self.new_index])
self.projects[self.new_index]['project_path'] = os.path.normpath(
self.fix_project_path_literals(os.path.join(disk, dir)))
else:
self.projects[self.new_index]['project_path'] = os.path.normpath(
self.fix_project_path_literals(os.path.join(disk, dir)))
self.projects[self.new_index]['disk'] = self.disks_from_ft[
self.disk_combobox.currentIndex()]
self.projects[self.new_index]['disk_id'] = self.projects[
self.new_index]['disk']['id']
# set project path to show where it will be created
self.project_path.setText(
self.projects[self.new_index]['project_path'])
def update_resolution(self):
# update all values in resolution
if self.resolution_w.text():
self.projects[self.new_index]['custom_attributes'][
"resolutionWidth"] = int(self.resolution_w.text())
if self.resolution_h.text():
self.projects[self.new_index]['custom_attributes'][
"resolutionHeight"] = int(self.resolution_h.text())
def _update_attributes_by_list_selection(self):
# generate actual selection index
self.new_index = self.listWidget.currentRow()
self.project_dir.setText('')
self.fps.setText('')
self.handles.setText('')
self.resolution_w.setText('')
self.resolution_h.setText('')
# update project properities widgets and write changes
# into project dictionaries
self.projects[self.new_index] = self._fill_project_attributes_widgets(
self.projects[self.new_index], self.new_index)
self.update_disk()
def _build_disk_path(self):
if self.platform == "Windows":
print(self.projects[self.index].keys())
print(self.projects[self.new_index]['disk'])
return self.projects[self.new_index]['disk'][
'name'], self.projects[self.new_index]['disk']['windows']
else:
return self.projects[self.new_index]['disk'][
'name'], self.projects[self.new_index]['disk']['unix']
def _get_all_schemas(self):
schemas_list = []
for s in self.schemas_from_ft:
# print d.keys()
# if 'Pokus' in s['name']:
# continue
schemas_list.append('{}'.format(s['name']))
print("\nschemas in ftrack: {}\n".format(schemas_list))
return schemas_list
def _get_all_disks(self):
disks_list = []
for d in self.disks_from_ft:
# print d.keys()
if self.platform == "Windows":
if 'Local drive' in d['name']:
d['windows'] = os.path.join(d['windows'],
os.getenv('USERNAME')
or os.getenv('USER')
or os.getenv('LOGNAME'))
disks_list.append('"{}" at {}'.format(d['name'], d['windows']))
else:
if 'Local drive' in d['name']:
d['unix'] = os.path.join(d['unix'], getpass.getuser())
disks_list.append('"{}" at {}'.format(d['name'], d['unix']))
return disks_list
def _get_projects_ftrack(self):
projects_lst = []
for project in self.projects_from_ft:
# print project.keys()
projects_dict = {}
for k in project.keys():
''' # TODO: delete this in production version '''
# if 'test' not in project['name']:
# continue
# print '{}: {}\n'.format(k, project[k])
if '_link' == k:
# print project[k]
content = project[k]
for kc in content[0].keys():
if content[0]['name']:
content[0][kc] = content[0][kc].encode(
'ascii', 'ignore').decode('ascii')
print('{}: {}\n'.format(kc, content[0][kc]))
projects_dict[k] = content
print(project[k])
print(projects_dict[k])
elif 'root' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k]
elif 'disk' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k]
elif 'name' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k].encode(
'ascii', 'ignore').decode('ascii')
elif 'disk_id' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k]
elif 'id' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k]
elif 'full_name' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k].encode(
'ascii', 'ignore').decode('ascii')
elif 'project_schema_id' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k]
elif 'project_schema' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k]
elif 'custom_attributes' == k:
print('{}: {}\n'.format(k, project[k]))
projects_dict[k] = project[k]
else:
pass
if projects_dict:
projects_lst.append(projects_dict)
return projects_lst
class Project_name_get(Project_name_getUI):
def __init__(self, parent=None):
super(Project_name_get, self).__init__(parent)
# self.input_project_name.textChanged.connect(self.input_project_name.placeholderText)
self.set_pushbutton.clicked.connect(lambda: self.execute())
self.cancel_pushbutton.clicked.connect(self.close)
self.listWidget.itemSelectionChanged.connect(
self._update_attributes_by_list_selection)
self.disk_combobox.currentIndexChanged.connect(self.update_disk)
self.schema_combobox.currentIndexChanged.connect(self.update_schema)
self.project_dir.textChanged.connect(self.update_disk)
self.fps.textChanged.connect(self.update_fps)
self.handles.textChanged.connect(self.update_handles)
self.resolution_w.textChanged.connect(self.update_resolution)
self.resolution_h.textChanged.connect(self.update_resolution)
def update_handles(self):
self.projects[self.new_index]['custom_attributes']['handles'] = int(
self.handles.text())
def update_fps(self):
self.projects[self.new_index]['custom_attributes']['fps'] = int(
self.fps.text())
def update_schema(self):
self.projects[self.new_index]['project_schema'] = self.schemas_from_ft[
self.schema_combobox.currentIndex()]
self.projects[self.new_index]['project_schema_id'] = self.projects[
self.new_index]['project_schema']['id']
def execute(self):
# import ft_utils
# import hiero
# get the project which has been selected
print("well and what")
# set the project as context and create entity
# entity is task created with the name of user which is creating it
# get the project_path and create dir if there is not any
print(self.projects[self.new_index]['project_path'].replace(
self.disk_combobox.currentText().split(' ')[-1].lower(), ''))
# get the schema and recreate a starting project regarding the selection
# set_hiero_template(project_schema=self.projects[self.new_index][
# 'project_schema']['name'])
# set all project properities
# project = hiero.core.Project()
# project.setFramerate(
# int(self.projects[self.new_index]['custom_attributes']['fps']))
# project.projectRoot()
# print 'handles: {}'.format(self.projects[self.new_index]['custom_attributes']['handles'])
# print 'resolution_width: {}'.format(self.projects[self.new_index]['custom_attributes']["resolutionWidth"])
# print 'resolution_width: {}'.format(self.projects[self.new_index]['custom_attributes']["resolutionHeight"])
# print "<< {}".format(self.projects[self.new_index])
# get path for the hrox file
# root = context.data('ftrackData')['Project']['root']
# hrox_script_path = ft_utils.getPathsYaml(taskid, templateList=templates, root=root)
# save the hrox into the correct path
self.session.commit()
self.close()
#
# def set_hiero_template(project_schema=None):
# import hiero
# hiero.core.closeAllProjects()
# hiero_plugin_path = [
# p for p in os.environ['HIERO_PLUGIN_PATH'].split(';')
# if 'hiero_plugin_path' in p
# ][0]
# path = os.path.normpath(
# os.path.join(hiero_plugin_path, 'Templates', project_schema + '.hrox'))
# print('---> path to template: {}'.format(path))
# return hiero.core.openProject(path)
# def set_out_ft_session():
# session = ftrack_api.Session()
# projects_to_ft = session.query('Project where status is active')
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
panel = Project_name_get()
panel.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

81
schema/session-3.0.json Normal file
View file

@ -0,0 +1,81 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "openpype:session-3.0",
"description": "The Avalon environment",
"type": "object",
"additionalProperties": true,
"required": [
"AVALON_PROJECT",
"AVALON_ASSET"
],
"properties": {
"AVALON_PROJECTS": {
"description": "Absolute path to root of project directories",
"type": "string",
"example": "/nas/projects"
},
"AVALON_PROJECT": {
"description": "Name of project",
"type": "string",
"pattern": "^\\w*$",
"example": "Hulk"
},
"AVALON_ASSET": {
"description": "Name of asset",
"type": "string",
"pattern": "^\\w*$",
"example": "Bruce"
},
"AVALON_TASK": {
"description": "Name of task",
"type": "string",
"pattern": "^\\w*$",
"example": "modeling"
},
"AVALON_APP": {
"description": "Name of host",
"type": "string",
"pattern": "^\\w*$",
"example": "maya2016"
},
"AVALON_DB": {
"description": "Name of database",
"type": "string",
"pattern": "^\\w*$",
"example": "avalon",
"default": "avalon"
},
"AVALON_LABEL": {
"description": "Nice name of Avalon, used in e.g. graphical user interfaces",
"type": "string",
"example": "Mindbender",
"default": "Avalon"
},
"AVALON_TIMEOUT": {
"description": "Wherever there is a need for a timeout, this is the default value.",
"type": "string",
"pattern": "^[0-9]*$",
"default": "1000",
"example": "1000"
},
"AVALON_INSTANCE_ID": {
"description": "Unique identifier for instances in a working file",
"type": "string",
"pattern": "^[\\w.]*$",
"default": "avalon.instance",
"example": "avalon.instance"
},
"AVALON_CONTAINER_ID": {
"description": "Unique identifier for a loaded representation in a working file",
"type": "string",
"pattern": "^[\\w.]*$",
"default": "avalon.container",
"example": "avalon.container"
}
}
}

View file

@ -106,7 +106,8 @@ install_requires = [
"dns",
# Python defaults (cx_Freeze skip them by default)
"dbm",
"sqlite3"
"sqlite3",
"dataclasses"
]
includes = []

105
start.py
View file

@ -897,6 +897,56 @@ def _bootstrap_from_code(use_version, use_staging):
return version_path
def _boot_validate_versions(use_version, local_version):
_print(f">>> Validating version [ {use_version} ]")
openpype_versions = bootstrap.find_openpype(include_zips=True,
staging=True)
openpype_versions += bootstrap.find_openpype(include_zips=True,
staging=False)
v: OpenPypeVersion
found = [v for v in openpype_versions if str(v) == use_version]
if not found:
_print(f"!!! Version [ {use_version} ] not found.")
list_versions(openpype_versions, local_version)
sys.exit(1)
# print result
version_path = bootstrap.get_version_path_from_list(
use_version, openpype_versions
)
valid, message = bootstrap.validate_openpype_version(version_path)
_print("{}{}".format(">>> " if valid else "!!! ", message))
def _boot_print_versions(use_staging, local_version, openpype_root):
if not use_staging:
_print("--- This will list only non-staging versions detected.")
_print(" To see staging versions, use --use-staging argument.")
else:
_print("--- This will list only staging versions detected.")
_print(" To see other version, omit --use-staging argument.")
openpype_versions = bootstrap.find_openpype(include_zips=True,
staging=use_staging)
if getattr(sys, 'frozen', False):
local_version = bootstrap.get_version(Path(openpype_root))
else:
local_version = OpenPypeVersion.get_installed_version_str()
list_versions(openpype_versions, local_version)
def _boot_handle_missing_version(local_version, use_staging, message):
_print(message)
if os.environ.get("OPENPYPE_HEADLESS_MODE") == "1":
openpype_versions = bootstrap.find_openpype(
include_zips=True, staging=use_staging
)
list_versions(openpype_versions, local_version)
else:
igniter.show_message_dialog("Version not found", message)
def boot():
"""Bootstrap OpenPype."""
@ -966,30 +1016,7 @@ def boot():
local_version = OpenPypeVersion.get_installed_version_str()
if "validate" in commands:
_print(f">>> Validating version [ {use_version} ]")
openpype_versions = bootstrap.find_openpype(include_zips=True,
staging=True)
openpype_versions += bootstrap.find_openpype(include_zips=True,
staging=False)
v: OpenPypeVersion
found = [v for v in openpype_versions if str(v) == use_version]
if not found:
_print(f"!!! Version [ {use_version} ] not found.")
list_versions(openpype_versions, local_version)
sys.exit(1)
# print result
result = bootstrap.validate_openpype_version(
bootstrap.get_version_path_from_list(
use_version, openpype_versions))
_print("{}{}".format(
">>> " if result[0] else "!!! ",
bootstrap.validate_openpype_version(
bootstrap.get_version_path_from_list(
use_version, openpype_versions)
)[1])
)
_boot_validate_versions(use_version, local_version)
sys.exit(1)
if not openpype_path:
@ -999,21 +1026,7 @@ def boot():
os.environ["OPENPYPE_PATH"] = openpype_path
if "print_versions" in commands:
if not use_staging:
_print("--- This will list only non-staging versions detected.")
_print(" To see staging versions, use --use-staging argument.")
else:
_print("--- This will list only staging versions detected.")
_print(" To see other version, omit --use-staging argument.")
_openpype_root = OPENPYPE_ROOT
openpype_versions = bootstrap.find_openpype(include_zips=True,
staging=use_staging)
if getattr(sys, 'frozen', False):
local_version = bootstrap.get_version(Path(_openpype_root))
else:
local_version = OpenPypeVersion.get_installed_version_str()
list_versions(openpype_versions, local_version)
_boot_print_versions(use_staging, local_version, OPENPYPE_ROOT)
sys.exit(1)
# ------------------------------------------------------------------------
@ -1026,12 +1039,7 @@ def boot():
try:
version_path = _find_frozen_openpype(use_version, use_staging)
except OpenPypeVersionNotFound as exc:
message = str(exc)
_print(message)
if os.environ.get("OPENPYPE_HEADLESS_MODE") == "1":
list_versions(openpype_versions, local_version)
else:
igniter.show_message_dialog("Version not found", message)
_boot_handle_missing_version(local_version, use_staging, str(exc))
sys.exit(1)
except RuntimeError as e:
@ -1050,12 +1058,7 @@ def boot():
version_path = _bootstrap_from_code(use_version, use_staging)
except OpenPypeVersionNotFound as exc:
message = str(exc)
_print(message)
if os.environ.get("OPENPYPE_HEADLESS_MODE") == "1":
list_versions(openpype_versions, local_version)
else:
igniter.show_message_dialog("Version not found", message)
_boot_handle_missing_version(local_version, use_staging, str(exc))
sys.exit(1)
# set this to point either to `python` from venv in case of live code

View file

@ -153,7 +153,7 @@ class ModuleUnitTest(BaseTest):
Database prepared from dumps with 'db_setup' fixture.
"""
from avalon.api import AvalonMongoDB
from openpype.pipeline import AvalonMongoDB
dbcon = AvalonMongoDB()
dbcon.Session["AVALON_PROJECT"] = self.TEST_PROJECT_NAME
yield dbcon