Пример #1
0
    def set_public_stamp(self, rigging_version, shading_version):
        if not self.public_task:
            raise RuntimeError

        rigging_origin_version = filter(
            lambda x: x["number"] == rigging_version,
            self.rigging_versions)[-1]
        rigging_origin_version = str(rigging_origin_version["number"])

        if self.require_shading:
            shading_origin_version = filter(
                lambda x: x["number"] == shading_version,
                self.shading_versions)[-1]
            shading_origin_version = str(shading_origin_version["number"])
        else:
            shading_origin_version = "0"

        if not "public_stamp" in self["publish"]:

            self["publish"]["public_stamp"] = {
                "ID": self["publish"]["sandbox"]["id"],
                "Version": self.public_version["suffix"],
                "Asset": self.asset["name"],
                "Root": self.asset["project"]["dir"]["path"],
                "Show": self.asset["project"]["name"],
                "Author": getpass.getuser(),
                "Date": str(datetime.datetime.now()),
                "Origin_rigging": rigging_origin_version,
                "Origin_shading": shading_origin_version,
            }

        else:
            lprint("public stamp already initiated")
    def execute(self):

        root = r'p:\MBA_SE02\tmp\publisher'

        job_key = next(iter(self.job_data['jobs']))
        asset_key = next(iter(self.job_data['jobs'][job_key]))
        asset_path = os.path.split(
            os.path.normpath(
                self.job_data['jobs'][job_key][asset_key][u"path"]))
        asset_name = asset_path[-1]
        asset_type = asset_path[-2]

        from MBA_SE02.internal.publish.apps import publisher_core
        data = {
            "root": root,
            "project": "MBA_SE02",
            "assetType": asset_type,
            "asset": asset_name,
            "note": "batch publish",
            "mode": publisher_core.Publish_mode.DRY,
            "require_animation": False,
            "render_preview": False,
            "render_test": True,
        }

        result = publisher_core.cli_execute(data)
        lprint(result)

        if not result["result"]:
            lprint("Failed maya_script_job")
            cmds.file(new=True, f=True)
            maya.standalone.uninitialize()
            os._exit(1)
Пример #3
0
    def _export(self, exportPath):

        id = self["publish"]["sandbox"]["id"]
        target_dir = nJoin(exportPath, id)
        assure_folder_exists(target_dir)

        target_rigging = nJoin(target_dir, '{}_rigging.ma'.format(id))
        target_shading = nJoin(target_dir, '{}_shading.ma'.format(id))
        target_animation = nJoin(target_dir, '{}_animation.ma'.format(id))
        target_test = nJoin(target_dir, '{}_test.ma'.format(id))
        target_data = nJoin(target_dir, '{}_data.json'.format(id))

        errors = []
        try:
            shutil.copy2(self["publish"]["sandbox"]["rigging"]["path"],
                         target_rigging)
        except:
            errors.append("failed to copy rigging file")

        try:
            shutil.copy2(self["publish"]["sandbox"]["shading"]["path"],
                         target_shading)
        except:
            errors.append("failed to copy shading file")

        try:
            shutil.copy2(self["publish"]["sandbox"]["animation"]["path"],
                         target_animation)
        except:
            errors.append("failed to copy animation file")
        # shutil.copy2(self["publish"]["sandbox"]["test"]["path"], target_test)

        exported_data = copy.deepcopy(self["publish"])
        exported_data["sandbox"]["base"] = target_dir
        exported_data["sandbox"]["rigging"]["path"] = target_rigging
        exported_data["sandbox"]["shading"]["path"] = target_shading
        exported_data["sandbox"]["animation"]["path"] = target_animation
        exported_data["sandbox"]["test"]["path"] = target_test

        self["publish"]["sandbox"]["base"] = target_dir
        self["publish"]["sandbox"]["rigging"]["path"] = target_rigging
        self["publish"]["sandbox"]["shading"]["path"] = target_shading
        self["publish"]["sandbox"]["animation"]["path"] = target_animation
        self["publish"]["sandbox"]["test"]["path"] = target_test

        with open(target_data, 'w') as DataFile:
            json.dump(exported_data, DataFile, indent=4)

        lprint("finished exporting data:")
        lprint(json.dumps(exported_data, indent=4))
        return errors
    def run(self):
        script_start = time.time()

        try:
            self.import_data_deadline()
            self.execute()

            lprint("Job complete in {}".format(
                format_duration(time.time() - script_start)))
            # Uninitialize is required to exit, otherwise mayapy freezes indefinitely.
            maya.standalone.uninitialize()
            os._exit(0)

        except Exception as e:
            traceback.print_exc()
            lprint(e)
            self.on_failed()
Пример #5
0
    def on_shading_processed_successfully(self, *args):
        from pipeline.variants.pipeline_maya.utils import maya_helper
        reload(maya_helper)

        try:
            assure_folder_exists(self["publish"]["sandbox"]["base"])
            maya_helper.save_scene_as(
                path=self["publish"]["sandbox"]["base"],
                file_name=os.path.basename(
                    self["publish"]["sandbox"]["shading"]["path"]))
            lprint("Temp shading master saved to: {}".format(
                self["publish"]["sandbox"]["shading"]))
            maya_helper.new_scene()
            self.update_process_state(Publisher.ready, "shading")

        except:
            lprint(traceback.format_exc())
            self.on_shading_processed_failed()
Пример #6
0
    def _import(self, importPath):
        id = os.path.basename(importPath)
        data_file = nJoin(importPath, "{}_data.json".format(id))
        if not os.path.isfile(data_file):
            raise RuntimeError

        with open(data_file, "r") as DataFile:
            data = json.load(DataFile)

        projects = sb_projects.SB_LibProjects(None)
        time.sleep(0.1)

        project = projects.get_project(data["asset"][0])
        props = project.getAssetType(data["asset"][2])
        asset = props.getAsset(data["asset"][3])
        self.init_asset(asset)
        self["publish"] = copy.deepcopy(data)

        lprint("finished importing data")
Пример #7
0
    def init_asset(self, asset=None):
        if not hasattr(self, "asset"):
            self.asset = asset

        if not self.asset:
            raise RuntimeError

        asset = self.asset

        self.public_task = asset.getTask("public")
        self.public_version = self.public_task['version_repository']["dir"][
            "next"]

        self.rigging_task = asset.getTask("rigging")
        self.rigging_versions = self.rigging_task["versions"]

        self.shading_task = asset.getTask("shading")
        self.shading_versions = self.shading_task["versions"]

        self.anim_tests_task = asset.getTask("anim_tests")
        self.anim_tests_versions = self.anim_tests_task["versions"]

        if (not self.anim_tests_versions) and (asset["variant"]):
            # maybe this is a variant?
            # let's get it's base asset
            base_asset = asset.dir['metadata_file']['json_data']['base_asset'][
                -1]
            project = asset['project']
            characters = project.get_asset_type("characters")
            base_asset = characters.get_asset(base_asset)

            self.anim_tests_task = base_asset.getTask("anim_tests")
            self.anim_tests_versions = self.anim_tests_task["versions"]

        ###################################################
        # the following data will be without any python objects - should be serializable
        self["publish"] = {}
        self["publish"]["asset"] = asset["lineage"]
        lprint("initiated with asset: {}".format(asset["lineage"]))
        self.set_sandbox()
Пример #8
0
    def process_rigging(self, rigging_version, shading_version):
        ##############################################################################################################################
        # the rigging should be processed in maya
        ##############################################################################################################################
        try:
            sl = self.get_selected_versions(rigging_version, shading_version)
            self.set_public_stamp(sl["rigging"]["number"],
                                  sl["shading"]["number"])

            import pymel.core as pm
            from MBA_SE02.internal.rigging import publish as rigging_publish
            from pipeline.variants.pipeline_maya.utils import maya_helper
            reload(rigging_publish)
            reload(maya_helper)

            lprint(sl["rigging"].dir["path"])
            maya_helper.open_scene(sl["rigging"].dir["path"])

            def process():
                publisher = rigging_publish.Rigging_publish(
                    public_stamp=self["publish"]["public_stamp"])
                # publisher.published_successfully.connect(self.on_rigging_processed_successfully)
                # publisher.published_failed.connect(self.on_rigging_processed_failed)
                result = publisher.start()
                if result:
                    self.on_rigging_processed_successfully()
                else:
                    self.on_rigging_processed_failed()

                return result

            # pm.evalDeferred(lambda: process())
            return process()

        except:
            lprint(traceback.format_exc())
            self.on_rigging_processed_failed()
 def on_failed(self):
     lprint("Failed maya_script_job")
     # Uninitialize is required to exit, otherwise mayapy freezes indefinitely.
     cmds.file(new=True, f=True)
     maya.standalone.uninitialize()
     os._exit(1)
# Mayapy script job template

from __future__ import print_function

from pipeline.utils import lprint

lprint("Initializing maya.standalone...")
# After running this, Maya will echo almost all logger output to stderr.
# Other threads might still write to stdout (e.g. vray), but we have no control over them from our thread.
import maya.standalone

maya.standalone.initialize(name="test")
p = r'P:\MBA_SE02\scripts\rigging\amit\automator\publisher\\'
if p not in sys.path:
    sys.path.append(p)

import os
import time
import traceback
from libSB.utils.text import format_duration

from maya import cmds
import maya.mel


class Publish_QA(object):
    """
        A Deadline job that creates and manages a queue of Signiant jobs based on data in a json file
    """
    def __init__(self):
        from libSB.sb_sync import SigniantLib
    def execute(self):

        job_key = next(iter(self.job_data['jobs']))
        asset_key = next(iter(self.job_data['jobs'][job_key]))
        asset_path = os.path.split(
            os.path.normpath(
                self.job_data['jobs'][job_key][asset_key][u"path"]))
        asset_name = asset_path[-1]
        asset_type = asset_path[-2]

        asset_path = os.path.join('P:/MBA_SE02', 'assets', asset_type,
                                  asset_name)
        asset_shading_json = os.path.join(asset_path, asset_name, 'shading',
                                          'shading.json')
        shading_versions_path = os.path.join(asset_path, 'shading', 'versions')

        current_file, version_number = versions_helper.get_latest_version_path_for_asset(
            shading_versions_path,
            asset_name,
            'shading',
            increment_version=False)

        cmds.file(new=True, force=True)

        try:
            cmds.file(current_file, o=True)
        except RuntimeError:
            # Maya will output other errors encountered during loading between the printed exception info and the "Warning: skipped" line.
            lprint(traceback.format_exc())
            lprint('Warning: skipped RuntimeError in scene load.')
        except:
            raise Exception(
                'Errors while loading scene - {}'.format(current_file))

        #####################################################################################

        lprint(
            '***************** START PROCESS ******************************')
        lprint('[piggy shading fix] finished loading:{}'.format(current_file))

        try:
            conn = pm.listConnections('piggy_baseRN', s=True, d=False, p=True)
            for con in conn:
                pm.disconnectAttr(con)

            shader = pm.PyNode("piggy_base:PiggyHair_Opacity_Offset")
            hairObjs = [
                'piggy_base:piggy_hair_offset_high',
                'piggy_base:piggy_ponytail_high_offset'
            ]

            shader_sg = pm.sets(renderable=True,
                                noSurfaceShader=True,
                                empty=True,
                                name="{}SG".format(shader.name()))
            shader.outColor.connect(shader_sg.surfaceShader)
            cmds.select(hairObjs)
            cmds.sets(e=True, forceElement=shader_sg.name())
        except:
            lprint(traceback.format_exc())
            raise Exception(
                '[piggy shading fix] Failed during code execution!')

        lprint('[piggy shading fix] Done!')
        lprint(
            '***************** FINISHED PROCESS ******************************'
        )
        #####################################################################################

        new_file, new_version_number = versions_helper.get_latest_version_path_for_asset(
            shading_versions_path,
            asset_name,
            'shading',
            increment_version=True)

        try:
            if not os.path.exists(os.path.dirname(new_file)):
                os.makedirs(os.path.dirname(new_file))

            cmds.file(rename=new_file)
            cmds.file(f=True, s=True, type="mayaAscii", op="v=1")
            lprint('[piggy shading fix] Saved new version {}'.format(new_file))
        except:
            lprint(traceback.format_exc())
            raise Exception(
                '[piggy shading fix] Unable to save new version - {}'.format(
                    new_file))

        if os.path.isfile(asset_shading_json):
            versions_helper.insert_metadata_version_entry(
                path=asset_shading_json,
                version_number=str(new_version_number),
                author="batch",
                note="piggy shading fix",
                key="versions",
                add_include=True)
            lprint('[piggy shading fix] Saved new metadata {}'.format(
                asset_shading_json))
Пример #12
0
    def process_animation(self, load=True):
        ##############################################################################################################################
        # the animation should be processed in maya
        ##############################################################################################################################
        try:
            sl = self.get_selected_versions()
            saved_animation = ''
            saved_camera = None
            if load:
                dir = sl["anim_test"]["parent"]['dir']["path"]
                anim = os.path.basename(sl["anim_test"]["path"])
                saved_animation = nJoin(dir, "studiolibrary",
                                        "{}.anim".format(anim))
                saved_camera = nJoin(dir, "camera", "{}.anim.ma".format(anim))
                if not os.path.exists(saved_camera):
                    saved_camera = None

                self['publish']['animation_camera'] = saved_camera

            if not os.path.isdir(saved_animation) and load:
                lprint("no animation was found in {}".format(saved_animation))
                raise Exception(
                    "no animation was found in {}".format(saved_animation))

            from maya import cmds
            from pipeline.variants.pipeline_maya.utils import maya_helper
            reload(maya_helper)

            import studiolibrary
            from mutils import animation

            maya_helper.new_scene()
            ns = '{}_0001'.format(self.asset["name"])
            cmds.file(self["publish"]["sandbox"]["rigging"]["path"],
                      r=True,
                      f=True,
                      ns=ns,
                      esn=False)

            if load:
                apply_animation = animation.Animation.fromPath(saved_animation)
                apply_animation.load(namespaces=[ns])

                sFrame = apply_animation.startFrame()
                eFrame = apply_animation.endFrame()
                cmds.playbackOptions(ast=sFrame)
                cmds.playbackOptions(aet=eFrame)

                if saved_camera:
                    cmds.file(saved_camera, i=True, pr=True)

            else:
                cmds.playbackOptions(ast=0)
                cmds.playbackOptions(aet=1)

            assure_folder_exists(self["publish"]["sandbox"]["base"])
            maya_helper.save_scene_as(
                path=self["publish"]["sandbox"]["base"],
                file_name=os.path.basename(
                    self["publish"]["sandbox"]["animation"]["path"]))

            self.update_process_state(Publisher.ready, "animation")
            return True
            #TODO: close file...
        except:
            lprint(traceback.format_exc())
            return False
Пример #13
0
def cli_execute(data):
    '''
    data {
        root: string
        project: string
        assetType: string
        asset: string
        note: string
        mode: Publish_mode
        require_animation: bool
    }

    '''

    exec_ = {"result": False, "data": {}}

    from libSB import sb_projects
    from libSB.sb_authentication.credentials import SBCredentialManager

    import maya.cmds as cmds

    lprint("Prior to init of SB_LibProjects")

    projects = sb_projects.SB_LibProjects(
        credentials=SBCredentialManager.batch_credentials)
    # projects.wait_for_online()
    import time
    time.sleep(3)

    lprint("Initiated SB_LibProjects")

    project = projects.get_project(data["project"])
    chars = project.getAssetType(data["assetType"])
    asset = chars.getAsset(data["asset"])

    pub = Publisher(root=data["root"])
    pub.init_asset(asset)
    rig = pub.rigging_versions[0]["number"]
    shd = pub.shading_versions[0]["number"]

    # import pprint
    # pprint.pprint(pub["publish"]['sandbox'])
    #
    #
    # print rig
    # print shd

    # # print os.path.basename(pub.anim_tests_versions[0]["path"])
    # sl = pub.get_selected_versions()
    #
    # dir = sl["anim_test"]["parent"]['dir']["path"]
    # print sl["anim_test"]
    # anim = os.path.basename(sl["anim_test"]["path"])
    # print dir
    # print anim
    #
    # return
    #

    if (data["require_animation"]) and (not pub.anim_tests_versions):
        lprint("No animation to load")
        exec_["data"] = pub["publish"]
        return exec_

    from pipeline.variants.pipeline_maya.utils import maya_helper
    reload(maya_helper)

    maya_helper.new_scene()
    try:
        res = pub.process_rigging(rig, shd)
        if not res: raise Exception()
    except:
        lprint(traceback.format_exc())
        lprint('Failed processing rig')
        exec_["data"] = pub["publish"]
        return exec_

    maya_helper.new_scene()
    try:
        res = pub.process_shading(rig, shd)
        if not res: raise Exception()
    except:
        lprint(traceback.format_exc())
        lprint('Failed processing shading')
        exec_["data"] = pub["publish"]
        return exec_

    maya_helper.new_scene()
    try:
        res = pub.process_animation(load=data["require_animation"])
        if not res: raise Exception()
    except:
        lprint(traceback.format_exc())
        lprint('Failed creating animation scene')
        exec_["data"] = pub["publish"]
        return exec_

    if data["render_preview"]:
        # let's export a take
        try:

            from MBA_SE02.internal.publish.blast import publish

            _data = {
                "id": pub["publish"]["sandbox"]["id"],
                "path": pub["publish"]["sandbox"]["base"],
                "asset_name": pub["publish"]["sandbox"]["asset_name"],
                "animation_camera": pub["publish"].get("animation_camera",
                                                       False)
            }
            pub_blast = publish.Asset_QA_blast(data=_data)
            res = pub_blast.start()
            if not res: raise Exception()

        except:
            lprint(traceback.format_exc())
            return exec_

    try:
        res = pub.process_test()
        if not res: raise Exception()
    except:
        lprint(traceback.format_exc())
        lprint('Failed processing assembly test')
        exec_["data"] = pub["publish"]
        return exec_

    try:
        # save the test scene
        cmds.file(rename=pub["publish"]["sandbox"]["test"]["path"])
        cmds.file(f=True, s=True, type="mayaAscii", op="v=1")
    except:
        lprint(traceback.format_exc())
        lprint('Failed saving test scene')
        exec_["data"] = pub["publish"]
        return exec_

    if data["render_test"]:
        # let's export a take
        try:

            from MBA_SE02.internal.publish.render import publish

            _data = {
                "id": pub["publish"]["sandbox"]["id"],
                "path": pub["publish"]["sandbox"]["base"],
                "asset_name": pub["publish"]["sandbox"]["asset_name"],
                "all_animation": data.get("all_animation", False),
                "animation_camera": pub["publish"].get("animation_camera",
                                                       False)
            }
            pub_blast = publish.Asset_QA_render(data=_data)
            res = pub_blast.start()
            if not res: raise Exception()

        except:
            lprint(traceback.format_exc())
            return exec_

    # print pub['publish']['sandbox']['base']
    if data["mode"] == Publish_mode.WET:
        try:
            res = pub.process_publish(note=data["note"])
            if not res: raise Exception()

            exec_["result"] = True
            return exec_

        except:
            lprint(traceback.format_exc())
            lprint('Failed publishing asset')
            exec_["data"] = pub["publish"]
            return exec_

    # completed with zero errors!
    exec_["result"] = True
    exec_["data"] = pub["publish"]
    return exec_
Пример #14
0
 def update_process_state(self, status, process):
     self["publish"]["sandbox"][process]["state"] = status
     lprint("{} Process: {}".format(process, status))
    def run(self):
        script_start = time.time()

        try:
            self.import_data_deadline()
            self.execute()

            lprint("Job complete in {}".format(
                format_duration(time.time() - script_start)))
            # Uninitialize is required to exit, otherwise mayapy freezes indefinitely.
            try:
                lprint("Attempt to uninitialize Maya session")
                cmds.file(new=True, f=True)
                lprint("My Test!!!!")
                maya.standalone.uninitialize(name="test")
                lprint("after uninitialize")
            except:
                lprint(traceback.format_exc())
            lprint("exiting")
            os._exit(0)
            lprint("after exit")

        except Exception as e:
            traceback.print_exc()
            lprint(e)
            self.on_failed()
Пример #16
0
 def __init__(self, message, traceback=None):
     super(PublishException, self).__init__(message)
     self._message = message
     if traceback:
         lprint(traceback)
Пример #17
0
    def process_publish(self, note=None):

        if note == "" or (not note):
            lprint('warning: must provide a note')
            raise PublishException("warning: must provide a note")

        # setup the copy paths
        public_path = self.public_task['version_repository']["dir"]["path"]
        next = self.public_task['version_repository']["dir"]["next"]
        dir = nJoin(public_path, next["suffix"])

        # this will not support xgen!!
        rigging_name = "{asset}_rigging_{version}.ma".format(
            asset=self.asset["name"], version=next["suffix"])
        rigging_name_mb = "{asset}_rigging_{version}.mb".format(
            asset=self.asset["name"], version=next["suffix"])
        shading_name = "{asset}_shading_{version}.ma".format(
            asset=self.asset["name"], version=next["suffix"])
        rigging = nJoin(dir, rigging_name)
        rigging_mb = nJoin(dir, rigging_name_mb)
        shading = nJoin(dir, shading_name)

        try:
            assure_folder_exists(dir)

            lprint("=== copying temp files: ===")
            lprint(self["publish"]["sandbox"]["shading"])
            lprint(self["publish"]["sandbox"]["rigging"])

            lprint("=== into public folders: ===")
            lprint(rigging)
            lprint(shading)

            lprint(self.public_task["master_rigging"]["dir"]["path"])
            lprint(self.public_task["master_shading"]["dir"]["path"])

            shutil.copy2(self["publish"]["sandbox"]["rigging"]["path"],
                         rigging)
            shutil.copy2(self["publish"]["sandbox"]["rigging"]["path_mb"],
                         rigging_mb)
            shutil.copy2(self["publish"]["sandbox"]["rigging"]["path"],
                         self.public_task["master_rigging"]["dir"]["path"])
            shutil.copy2(self["publish"]["sandbox"]["rigging"]["path_mb"],
                         self.public_task["master_rigging_mb"]["dir"]["path"])

            if self.require_shading:
                shutil.copy2(self["publish"]["sandbox"]["shading"]["path"],
                             shading)
                shutil.copy2(self["publish"]["sandbox"]["shading"]["path"],
                             self.public_task["master_shading"]["dir"]["path"])

            lprint("=== done copy ===")
        except:
            raise PublishException("warning: errors during files copying",
                                   traceback=traceback.format_exc())

        try:
            data_helper.insert_metadata_version_entry(
                path=self.public_task["dir"]["metadata_file"]["path"],
                version_number=[next["number"], str(0)],
                author=self["publish"]["public_stamp"]["Author"],
                note=note,
                key='versions',
                add_include=False,
                origin={
                    "rigging":
                    self["publish"]["public_stamp"]["Origin_rigging"],
                    "shading":
                    self["publish"]["public_stamp"]["Origin_shading"]
                })
        except:
            raise PublishException("warning: errors during metadata setup",
                                   traceback=traceback.format_exc())

        ##############################################################
        # Sync with Signiant
        ##############################################################
        with SyncContext(dependencies=DependencyType.RECURSIVE_PARTIAL,
                         description='Publishing of: {}'.format(
                             self.asset['name']),
                         priority=98) as sync:
            sync.append(self.public_task["master_rigging"]["dir"]["path"])
            sync.append(self.public_task["master_rigging_mb"]["dir"]["path"])
            sync.append(self.public_task["master_shading"]["dir"]["path"])
            sync.append(self.public_task["dir"]["metadata_file"]["path"])

        with SyncContext(dependencies=DependencyType.NONE,
                         description='Publishing of (aux data): {}'.format(
                             self.asset['name']),
                         priority=70) as sync:
            git_repo_path = os.path.join(self.rigging_task['dir']['path'],
                                         self.asset['name'])
            sync.append(git_repo_path)
            sync.append(rigging)
            sync.append(rigging_mb)
            sync.append(shading)
        ##############################################################

        try:
            self.public_task["parent"].add_note("Maya: {}".format(note))
        except:
            lprint("warning: failed to save note to ftrack - {}".format(
                traceback=traceback.format_exc()))
            # raise PublishException("warning: failed to save note to ftrack", traceback=traceback.format_exc())

        return {"public_path": public_path, "next": next}
 def import_data_deadline(self):
     lprint("Getting data from Deadline")
     self.current_job = self.libdeadline['current_job']
     self.job_data = self.current_job['extra_info']['task_data']
     lprint(self.job_data)
Пример #19
0
from pipeline.utils import lprint
lprint("i'm in publisher test!!!")

import os
import sys
import functools
import shutil
import uuid
import tempfile
import traceback
import getpass
import datetime
import json
import copy
import time
from enum import Enum
# from sb_libs.latest.Qt import QtWidgets, QtCore, QtGui
from pipeline.utils import lprint, nJoin, assure_folder_exists
# from pipeline.widgets import Combo, PromptUser, UserMassage, GroupInput
# from pipeline.thread_helper import Thread
import pipeline
from pipeline import data_helper
from libSB.sb_sync import SyncContext, DependencyType

from libSB import sb_projects
from libSB.sb_standard_lib import Dictlike

# from libSB.sb_filesystem.types import SB_File
# from libSB.sb_site import SBSiteLib
# from libSB.sb_path import StorageMapping