Merge branch 'develop' into feature/PYPE-540_muster-pools-in-renderglobals

This commit is contained in:
Ondrej Samohel 2019-10-07 16:12:55 +02:00
commit 49adc09218
19 changed files with 360 additions and 25 deletions

View file

@ -0,0 +1,20 @@
"""
Requires:
None
Provides:
context -> anatomy (pypeapp.Anatomy)
"""
from pypeapp import Anatomy
import pyblish.api
class CollectAnatomy(pyblish.api.ContextPlugin):
"""Collect Anatomy into Context"""
order = pyblish.api.CollectorOrder
label = "Collect Anatomy"
def process(self, context):
context.data['anatomy'] = Anatomy()
self.log.info("Anatomy templates collected...")

View file

@ -1,3 +1,10 @@
"""
Requires:
None
Provides:
context -> comment (str)
"""
import pyblish.api import pyblish.api

View file

@ -1,3 +1,18 @@
"""
Requires:
environment -> SAPUBLISH_INPATH
environment -> SAPUBLISH_OUTPATH
Provides:
context -> returnJsonPath (str)
context -> project
context -> asset
instance -> destination_list (list)
instance -> representations (list)
instance -> source (list)
instance -> representations
"""
import os import os
import pyblish.api import pyblish.api
from avalon import io from avalon import io
@ -31,9 +46,25 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin):
in_data = json.load(f) in_data = json.load(f)
asset_name = in_data['asset'] asset_name = in_data['asset']
family_preset_key = in_data.get('family_preset_key', '')
family = in_data['family'] family = in_data['family']
subset = in_data['subset'] subset = in_data['subset']
# Load presets
presets = context.data.get("presets")
if not presets:
from pypeapp import config
presets = config.get_presets()
# Get from presets anatomy key that will be used for getting template
# - default integrate new is used if not set
anatomy_key = presets.get(
"standalone_publish", {}).get(
"families", {}).get(
family_preset_key, {}).get(
"anatomy_template"
)
project = io.find_one({'type': 'project'}) project = io.find_one({'type': 'project'})
asset = io.find_one({ asset = io.find_one({
'type': 'asset', 'type': 'asset',
@ -50,6 +81,8 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin):
"label": subset, "label": subset,
"name": subset, "name": subset,
"family": family, "family": family,
"frameStart": in_data.get("representations", [None])[0].get("frameStart", None),
"frameEnd": in_data.get("representations", [None])[0].get("frameEnd", None),
"families": [family, 'ftrack'], "families": [family, 'ftrack'],
}) })
self.log.info("collected instance: {}".format(instance.data)) self.log.info("collected instance: {}".format(instance.data))
@ -63,7 +96,9 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin):
component['destination'] = component['files'] component['destination'] = component['files']
component['stagingDir'] = component['stagingDir'] component['stagingDir'] = component['stagingDir']
component['anatomy_template'] = 'render' # Do not set anatomy_template if not specified
if anatomy_key:
component['anatomy_template'] = anatomy_key
if isinstance(component['files'], list): if isinstance(component['files'], list):
collections, remainder = clique.assemble(component['files']) collections, remainder = clique.assemble(component['files'])
self.log.debug("collecting sequence: {}".format(collections)) self.log.debug("collecting sequence: {}".format(collections))

View file

@ -1,3 +1,10 @@
"""
Requires:
context -> currentFile (str)
Provides:
context -> label (str)
"""
import os import os
import pyblish.api import pyblish.api

View file

@ -1,3 +1,11 @@
"""
Requires:
None
Provides:
context -> currentFile (str)
"""
import os import os
import pyblish.api import pyblish.api

View file

@ -1,3 +1,11 @@
"""
Requires:
environment -> DEADLINE_PATH
Provides:
context -> deadlineUser (str)
"""
import os import os
import subprocess import subprocess
@ -54,4 +62,3 @@ class CollectDeadlineUser(pyblish.api.ContextPlugin):
self.log.info("Found Deadline user: {}".format(user)) self.log.info("Found Deadline user: {}".format(user))
context.data['deadlineUser'] = user context.data['deadlineUser'] = user

View file

@ -1,3 +1,13 @@
"""
Requires:
environment -> PYPE_PUBLISH_PATHS
context -> workspaceDir
Provides:
context -> user (str)
instance -> new instance
"""
import os import os
import re import re
import copy import copy

View file

@ -1,3 +1,11 @@
"""
Requires:
none
Provides:
context -> machine (str)
"""
import pyblish.api import pyblish.api

View file

@ -1,5 +1,11 @@
import os """
import json Requires:
config_data -> ftrack.output_representation
Provides:
context -> output_repre_config (str)
"""
import pyblish.api import pyblish.api
from pypeapp import config from pypeapp import config
@ -9,7 +15,7 @@ class CollectOutputRepreConfig(pyblish.api.ContextPlugin):
order = pyblish.api.CollectorOrder order = pyblish.api.CollectorOrder
label = "Collect Config for representation" label = "Collect Config for representation"
hosts = ["shell"] hosts = ["shell", "standalonepublisher"]
def process(self, context): def process(self, context):
config_data = config.get_presets()["ftrack"]["output_representation"] config_data = config.get_presets()["ftrack"]["output_representation"]

View file

@ -1,3 +1,12 @@
"""
Requires:
config_data -> colorspace.default
config_data -> dataflow.default
Provides:
context -> presets
"""
from pyblish import api from pyblish import api
from pypeapp import config from pypeapp import config
@ -5,7 +14,7 @@ from pypeapp import config
class CollectPresets(api.ContextPlugin): class CollectPresets(api.ContextPlugin):
"""Collect Presets.""" """Collect Presets."""
order = api.CollectorOrder order = api.CollectorOrder - 0.491
label = "Collect Presets" label = "Collect Presets"
def process(self, context): def process(self, context):

View file

@ -1,8 +1,15 @@
"""
Requires:
None
Provides:
context -> projectData
"""
import pyblish.api import pyblish.api
import pype.api as pype import pype.api as pype
class CollectProjectData(pyblish.api.ContextPlugin): class CollectProjectData(pyblish.api.ContextPlugin):
"""Collecting project data from avalon db""" """Collecting project data from avalon db"""

View file

@ -13,6 +13,8 @@ class CollectSceneVersion(pyblish.api.ContextPlugin):
label = 'Collect Version' label = 'Collect Version'
def process(self, context): def process(self, context):
if "standalonepublisher" in context.data.get("host"):
return
filename = os.path.basename(context.data.get('currentFile')) filename = os.path.basename(context.data.get('currentFile'))

View file

@ -1,16 +1,86 @@
"""
Requires:
session -> AVALON_PROJECT
context -> anatomy (pypeapp.Anatomy)
instance -> subset
instance -> asset
instance -> family
import pype.api as pype Provides:
from pypeapp import Anatomy instance -> template
instance -> assumedTemplateData
instance -> assumedDestination
"""
import os
from avalon import io, api
import pyblish.api import pyblish.api
class CollectTemplates(pyblish.api.ContextPlugin): class CollectTemplates(pyblish.api.InstancePlugin):
"""Inject the current working file into context""" """Fill templates with data needed for publish"""
order = pyblish.api.CollectorOrder order = pyblish.api.CollectorOrder + 0.1
label = "Collect Templates" label = "Collect and fill Templates"
def process(self, context): def process(self, instance):
context.data['anatomy'] = Anatomy() # get all the stuff from the database
self.log.info("Anatomy templates collected...") subset_name = instance.data["subset"]
asset_name = instance.data["asset"]
project_name = api.Session["AVALON_PROJECT"]
project = io.find_one({"type": "project",
"name": project_name},
projection={"config": True, "data": True})
template = project["config"]["template"]["publish"]
anatomy = instance.context.data['anatomy']
asset = io.find_one({"type": "asset",
"name": asset_name,
"parent": project["_id"]})
assert asset, ("No asset found by the name '{}' "
"in project '{}'".format(asset_name, project_name))
silo = asset['silo']
subset = io.find_one({"type": "subset",
"name": subset_name,
"parent": asset["_id"]})
# assume there is no version yet, we start at `1`
version = None
version_number = 1
if subset is not None:
version = io.find_one({"type": "version",
"parent": subset["_id"]},
sort=[("name", -1)])
# if there is a subset there ought to be version
if version is not None:
version_number += int(version["name"])
hierarchy = asset['data']['parents']
if hierarchy:
# hierarchy = os.path.sep.join(hierarchy)
hierarchy = os.path.join(*hierarchy)
template_data = {"root": api.Session["AVALON_PROJECTS"],
"project": {"name": project_name,
"code": project['data']['code']},
"silo": silo,
"family": instance.data['family'],
"asset": asset_name,
"subset": subset_name,
"version": version_number,
"hierarchy": hierarchy,
"representation": "TEMP"}
instance.data["template"] = template
instance.data["assumedTemplateData"] = template_data
# We take the parent folder of representation 'filepath'
instance.data["assumedDestination"] = os.path.dirname(
(anatomy.format(template_data))["publish"]["path"]
)

View file

@ -0,0 +1,126 @@
import os
import tempfile
import subprocess
import pyblish.api
import pype.api
class ExtractThumbnail(pyblish.api.InstancePlugin):
"""Extract jpeg thumbnail from component input from standalone publisher
Uses jpeg file from component if possible (when single or multiple jpegs
are loaded to component selected as thumbnail) otherwise extracts from
input file/s single jpeg to temp.
"""
label = "Extract Thumbnail"
hosts = ["standalonepublisher"]
order = pyblish.api.ExtractorOrder
def process(self, instance):
repres = instance.data.get('representations')
if not repres:
return
thumbnail_repre = None
for repre in repres:
if repre.get("thumbnail"):
thumbnail_repre = repre
break
if not thumbnail_repre:
return
files = thumbnail_repre.get("files")
if not files:
return
if isinstance(files, list):
files_len = len(files)
file = str(files[0])
else:
files_len = 1
file = files
is_jpeg = False
if file.endswith(".jpeg") or file.endswith(".jpg"):
is_jpeg = True
if is_jpeg and files_len == 1:
# skip if already is single jpeg file
return
elif is_jpeg:
# use first frame as thumbnail if is sequence of jpegs
full_thumbnail_path = file
self.log.info(
"For thumbnail is used file: {}".format(full_thumbnail_path)
)
else:
# Convert to jpeg if not yet
full_input_path = os.path.join(thumbnail_repre["stagingDir"], file)
self.log.info("input {}".format(full_input_path))
full_thumbnail_path = tempfile.mkstemp(suffix=".jpg")[1]
self.log.info("output {}".format(full_thumbnail_path))
config_data = instance.context.data.get("output_repre_config", {})
proj_name = os.environ.get("AVALON_PROJECT", "__default__")
profile = config_data.get(
proj_name,
config_data.get("__default__", {})
)
ffmpeg_path = os.getenv("FFMPEG_PATH", "")
if ffmpeg_path:
ffmpeg_path += "/ffmpeg"
else:
ffmpeg_path = "ffmpeg"
jpeg_items = []
jpeg_items.append(ffmpeg_path)
# override file if already exists
jpeg_items.append("-y")
# add input filters from peresets
if profile:
jpeg_items.extend(profile.get('input', []))
# input file
jpeg_items.append("-i {}".format(full_input_path))
# extract only single file
jpeg_items.append("-vframes 1")
# output file
jpeg_items.append(full_thumbnail_path)
subprocess_jpeg = " ".join(jpeg_items)
# run subprocess
self.log.debug("Executing: {}".format(subprocess_jpeg))
subprocess.Popen(
subprocess_jpeg,
stdout=subprocess.PIPE,
shell=True
)
# remove thumbnail key from origin repre
thumbnail_repre.pop("thumbnail")
filename = os.path.basename(full_thumbnail_path)
staging_dir = os.path.dirname(full_thumbnail_path)
# create new thumbnail representation
representation = {
'name': 'jpg',
'ext': 'jpg',
'files': filename,
"stagingDir": staging_dir,
"thumbnail": True,
"tags": []
}
# # add Delete tag when temp file was rendered
# if not is_jpeg:
# representation["tags"].append("delete")
instance.data["representations"].append(representation)

View file

@ -30,7 +30,8 @@ class IntegrateAssumedDestination(pyblish.api.InstancePlugin):
"resources") "resources")
# Clean the path # Clean the path
mock_destination = os.path.abspath(os.path.normpath(mock_destination)).replace("\\", "/") mock_destination = os.path.abspath(
os.path.normpath(mock_destination)).replace("\\", "/")
# Define resource destination and transfers # Define resource destination and transfers
resources = instance.data.get("resources", list()) resources = instance.data.get("resources", list())
@ -38,7 +39,8 @@ class IntegrateAssumedDestination(pyblish.api.InstancePlugin):
for resource in resources: for resource in resources:
# Add destination to the resource # Add destination to the resource
source_filename = os.path.basename(resource["source"]).replace("\\", "/") source_filename = os.path.basename(
resource["source"]).replace("\\", "/")
destination = os.path.join(mock_destination, source_filename) destination = os.path.join(mock_destination, source_filename)
# Force forward slashes to fix issue with software unable # Force forward slashes to fix issue with software unable
@ -53,7 +55,8 @@ class IntegrateAssumedDestination(pyblish.api.InstancePlugin):
files = resource['files'] files = resource['files']
for fsrc in files: for fsrc in files:
fname = os.path.basename(fsrc) fname = os.path.basename(fsrc)
fdest = os.path.join(mock_destination, fname).replace("\\", "/") fdest = os.path.join(
mock_destination, fname).replace("\\", "/")
transfers.append([fsrc, fdest]) transfers.append([fsrc, fdest])
instance.data["resources"] = resources instance.data["resources"] = resources

View file

@ -103,7 +103,7 @@ def avalon_api_publish(data, gui=True):
"-pp", os.pathsep.join(pyblish.api.registered_paths()) "-pp", os.pathsep.join(pyblish.api.registered_paths())
] ]
os.environ["PYBLISH_HOSTS"] = "shell" os.environ["PYBLISH_HOSTS"] = "standalonepublisher"
os.environ["SAPUBLISH_INPATH"] = json_data_path os.environ["SAPUBLISH_INPATH"] = json_data_path
if gui: if gui:
@ -139,7 +139,7 @@ def cli_publish(data, gui=True):
if gui: if gui:
args += ["gui"] args += ["gui"]
os.environ["PYBLISH_HOSTS"] = "shell" os.environ["PYBLISH_HOSTS"] = "standalonepublisher"
os.environ["SAPUBLISH_INPATH"] = json_data_path os.environ["SAPUBLISH_INPATH"] = json_data_path
os.environ["SAPUBLISH_OUTPATH"] = return_data_path os.environ["SAPUBLISH_OUTPATH"] = return_data_path

View file

@ -6,6 +6,7 @@ HelpRole = QtCore.Qt.UserRole + 2
FamilyRole = QtCore.Qt.UserRole + 3 FamilyRole = QtCore.Qt.UserRole + 3
ExistsRole = QtCore.Qt.UserRole + 4 ExistsRole = QtCore.Qt.UserRole + 4
PluginRole = QtCore.Qt.UserRole + 5 PluginRole = QtCore.Qt.UserRole + 5
PluginKeyRole = QtCore.Qt.UserRole + 6
from ..resources import get_resource from ..resources import get_resource
from .button_from_svgs import SvgResizable, SvgButton from .button_from_svgs import SvgResizable, SvgButton

View file

@ -220,15 +220,21 @@ class DropDataFrame(QtWidgets.QFrame):
self._process_data(data) self._process_data(data)
def load_data_with_probe(self, filepath): def load_data_with_probe(self, filepath):
ffprobe_path = os.getenv("FFMPEG_PATH", "")
if ffprobe_path:
ffprobe_path += '/ffprobe'
else:
ffprobe_path = 'ffprobe'
args = [ args = [
'ffprobe', ffprobe_path,
'-v', 'quiet', '-v', 'quiet',
'-print_format', 'json', '-print_format', 'json',
'-show_format', '-show_format',
'-show_streams', filepath '-show_streams', filepath
] ]
ffprobe_p = subprocess.Popen( ffprobe_p = subprocess.Popen(
args, ' '.join(args),
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
shell=True shell=True
) )

View file

@ -5,7 +5,7 @@ import json
from collections import namedtuple from collections import namedtuple
from . import QtWidgets, QtCore from . import QtWidgets, QtCore
from . import HelpRole, FamilyRole, ExistsRole, PluginRole from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole
from . import FamilyDescriptionWidget from . import FamilyDescriptionWidget
from pypeapp import config from pypeapp import config
@ -116,8 +116,10 @@ class FamilyWidget(QtWidgets.QWidget):
def collect_data(self): def collect_data(self):
plugin = self.list_families.currentItem().data(PluginRole) plugin = self.list_families.currentItem().data(PluginRole)
key = self.list_families.currentItem().data(PluginKeyRole)
family = plugin.family.rsplit(".", 1)[-1] family = plugin.family.rsplit(".", 1)[-1]
data = { data = {
'family_preset_key': key,
'family': family, 'family': family,
'subset': self.input_result.text(), 'subset': self.input_result.text(),
'version': self.version_spinbox.value() 'version': self.version_spinbox.value()
@ -318,7 +320,7 @@ class FamilyWidget(QtWidgets.QWidget):
has_families = False has_families = False
presets = config.get_presets().get('standalone_publish', {}) presets = config.get_presets().get('standalone_publish', {})
for creator in presets.get('families', {}).values(): for key, creator in presets.get('families', {}).items():
creator = namedtuple("Creator", creator.keys())(*creator.values()) creator = namedtuple("Creator", creator.keys())(*creator.values())
label = creator.label or creator.family label = creator.label or creator.family
@ -327,6 +329,7 @@ class FamilyWidget(QtWidgets.QWidget):
item.setData(HelpRole, creator.help or "") item.setData(HelpRole, creator.help or "")
item.setData(FamilyRole, creator.family) item.setData(FamilyRole, creator.family)
item.setData(PluginRole, creator) item.setData(PluginRole, creator)
item.setData(PluginKeyRole, key)
item.setData(ExistsRole, False) item.setData(ExistsRole, False)
self.list_families.addItem(item) self.list_families.addItem(item)