diff --git a/openpype/hosts/hiero/otio/hiero_export.py b/openpype/hosts/hiero/otio/hiero_export.py index ccc05d5fd7..af4322e3d9 100644 --- a/openpype/hosts/hiero/otio/hiero_export.py +++ b/openpype/hosts/hiero/otio/hiero_export.py @@ -378,6 +378,17 @@ def add_otio_metadata(otio_item, media_source, **kwargs): def create_otio_timeline(): + def set_prev_item(itemindex, track_item): + # Add Gap if needed + if itemindex == 0: + # if it is first track item at track then add + # it to previouse item + return track_item + + else: + # get previouse item + return track_item.parent().items()[itemindex - 1] + # get current timeline self.timeline = hiero.ui.activeSequence() self.project_fps = self.timeline.framerate().toFloat() @@ -396,14 +407,6 @@ def create_otio_timeline(): type(track), track.name()) for itemindex, track_item in enumerate(track): - # skip offline track items - if not track_item.isMediaPresent(): - continue - - # skip if track item is disabled - if not track_item.isEnabled(): - continue - # Add Gap if needed if itemindex == 0: # if it is first track item at track then add diff --git a/openpype/hosts/hiero/plugins/publish/precollect_instances.py b/openpype/hosts/hiero/plugins/publish/precollect_instances.py index 936ea2be58..85b4e273d5 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_instances.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_instances.py @@ -131,7 +131,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin): self.create_shot_instance(context, **data) self.log.info("Creating instance: {}".format(instance)) - self.log.debug( + self.log.info( "_ instance.data: {}".format(pformat(instance.data))) if not with_audio: diff --git a/openpype/hosts/hiero/plugins/publish/precollect_workfile.py b/openpype/hosts/hiero/plugins/publish/precollect_workfile.py index ff5d516065..7db155048f 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_workfile.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_workfile.py @@ -8,6 +8,7 @@ from openpype.hosts.hiero.otio import hiero_export from Qt.QtGui import QPixmap import tempfile + class PrecollectWorkfile(pyblish.api.ContextPlugin): """Inject the current working file into context""" diff --git a/openpype/hosts/maya/api/__init__.py b/openpype/hosts/maya/api/__init__.py index db4dbf29c5..3412803714 100644 --- a/openpype/hosts/maya/api/__init__.py +++ b/openpype/hosts/maya/api/__init__.py @@ -35,6 +35,7 @@ def install(): pyblish.register_plugin_path(PUBLISH_PATH) avalon.register_plugin_path(avalon.Loader, LOAD_PATH) avalon.register_plugin_path(avalon.Creator, CREATE_PATH) + avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) log.info(PUBLISH_PATH) menu.install() diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 121f7a08a7..448cb814d9 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -4,6 +4,53 @@ import avalon.maya from openpype.api import PypeCreatorMixin +def get_reference_node(members, log=None): + """Get the reference node from the container members + Args: + members: list of node names + + Returns: + str: Reference node name. + + """ + + from maya import cmds + + # Collect the references without .placeHolderList[] attributes as + # unique entries (objects only) and skipping the sharedReferenceNode. + references = set() + for ref in cmds.ls(members, exactType="reference", objectsOnly=True): + + # Ignore any `:sharedReferenceNode` + if ref.rsplit(":", 1)[-1].startswith("sharedReferenceNode"): + continue + + # Ignore _UNKNOWN_REF_NODE_ (PLN-160) + if ref.rsplit(":", 1)[-1].startswith("_UNKNOWN_REF_NODE_"): + continue + + references.add(ref) + + assert references, "No reference node found in container" + + # Get highest reference node (least parents) + highest = min(references, + key=lambda x: len(get_reference_node_parents(x))) + + # Warn the user when we're taking the highest reference node + if len(references) > 1: + if not log: + from openpype.lib import PypeLogger + + log = PypeLogger().get_logger(__name__) + + log.warning("More than one reference node found in " + "container, using highest reference node: " + "%s (in: %s)", highest, list(references)) + + return highest + + def get_reference_node_parents(ref): """Return all parent reference nodes of reference node @@ -109,7 +156,7 @@ class ReferenceLoader(api.Loader): loader=self.__class__.__name__ )) else: - ref_node = self._get_reference_node(nodes) + ref_node = get_reference_node(nodes, self.log) loaded_containers.append(containerise( name=name, namespace=namespace, @@ -126,46 +173,6 @@ class ReferenceLoader(api.Loader): """To be implemented by subclass""" raise NotImplementedError("Must be implemented by subclass") - def _get_reference_node(self, members): - """Get the reference node from the container members - Args: - members: list of node names - - Returns: - str: Reference node name. - - """ - - from maya import cmds - - # Collect the references without .placeHolderList[] attributes as - # unique entries (objects only) and skipping the sharedReferenceNode. - references = set() - for ref in cmds.ls(members, exactType="reference", objectsOnly=True): - - # Ignore any `:sharedReferenceNode` - if ref.rsplit(":", 1)[-1].startswith("sharedReferenceNode"): - continue - - # Ignore _UNKNOWN_REF_NODE_ (PLN-160) - if ref.rsplit(":", 1)[-1].startswith("_UNKNOWN_REF_NODE_"): - continue - - references.add(ref) - - assert references, "No reference node found in container" - - # Get highest reference node (least parents) - highest = min(references, - key=lambda x: len(get_reference_node_parents(x))) - - # Warn the user when we're taking the highest reference node - if len(references) > 1: - self.log.warning("More than one reference node found in " - "container, using highest reference node: " - "%s (in: %s)", highest, list(references)) - - return highest def update(self, container, representation): @@ -178,7 +185,7 @@ class ReferenceLoader(api.Loader): # Get reference node from container members members = cmds.sets(node, query=True, nodesOnly=True) - reference_node = self._get_reference_node(members) + reference_node = get_reference_node(members, self.log) file_type = { "ma": "mayaAscii", @@ -274,7 +281,7 @@ class ReferenceLoader(api.Loader): # Assume asset has been referenced members = cmds.sets(node, query=True) - reference_node = self._get_reference_node(members) + reference_node = get_reference_node(members, self.log) assert reference_node, ("Imported container not supported; " "container must be referenced.") diff --git a/openpype/hosts/maya/plugins/inventory/import_reference.py b/openpype/hosts/maya/plugins/inventory/import_reference.py new file mode 100644 index 0000000000..2fa132a867 --- /dev/null +++ b/openpype/hosts/maya/plugins/inventory/import_reference.py @@ -0,0 +1,29 @@ +from maya import cmds + +from avalon import api + +from openpype.hosts.maya.api.plugin import get_reference_node + + +class ImportReference(api.InventoryAction): + """Imports selected reference to inside of the file.""" + + label = "Import Reference" + icon = "download" + color = "#d8d8d8" + + def process(self, containers): + references = cmds.ls(type="reference") + for container in containers: + if container["loader"] != "ReferenceLoader": + print("Not a reference, skipping") + continue + + node = container["objectName"] + members = cmds.sets(node, query=True, nodesOnly=True) + ref_node = get_reference_node(members) + + ref_file = cmds.referenceQuery(ref_node, f=True) + cmds.file(ref_file, importReference=True) + + return True # return anything to trigger model refresh diff --git a/openpype/hosts/nuke/plugins/publish/increment_script_version.py b/openpype/hosts/nuke/plugins/publish/increment_script_version.py index 47fccb9125..f55ed21ee2 100644 --- a/openpype/hosts/nuke/plugins/publish/increment_script_version.py +++ b/openpype/hosts/nuke/plugins/publish/increment_script_version.py @@ -9,7 +9,7 @@ class IncrementScriptVersion(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder + 0.9 label = "Increment Script Version" optional = True - families = ["workfile", "render", "render.local", "render.farm"] + families = ["workfile"] hosts = ['nuke'] def process(self, context): diff --git a/openpype/modules/default_modules/clockify/clockify_module.py b/openpype/modules/default_modules/clockify/clockify_module.py index 0de62d8ba4..932ce87c36 100644 --- a/openpype/modules/default_modules/clockify/clockify_module.py +++ b/openpype/modules/default_modules/clockify/clockify_module.py @@ -10,16 +10,14 @@ from .constants import ( from openpype.modules import OpenPypeModule from openpype_interfaces import ( ITrayModule, - IPluginPaths, - IFtrackEventHandlerPaths + IPluginPaths ) class ClockifyModule( OpenPypeModule, ITrayModule, - IPluginPaths, - IFtrackEventHandlerPaths + IPluginPaths ): name = "clockify" @@ -93,8 +91,8 @@ class ClockifyModule( "actions": [actions_path] } - def get_event_handler_paths(self): - """Implementaton of IFtrackEventHandlerPaths to get plugin paths.""" + def get_ftrack_event_handler_paths(self): + """Function for Ftrack module to add ftrack event handler paths.""" return { "user": [CLOCKIFY_FTRACK_USER_PATH], "server": [CLOCKIFY_FTRACK_SERVER_PATH] diff --git a/openpype/modules/default_modules/ftrack/ftrack_module.py b/openpype/modules/default_modules/ftrack/ftrack_module.py index 3732e762b4..c73f9b100d 100644 --- a/openpype/modules/default_modules/ftrack/ftrack_module.py +++ b/openpype/modules/default_modules/ftrack/ftrack_module.py @@ -8,8 +8,7 @@ from openpype_interfaces import ( ITrayModule, IPluginPaths, ILaunchHookPaths, - ISettingsChangeListener, - IFtrackEventHandlerPaths + ISettingsChangeListener ) from openpype.settings import SaveWarningExc @@ -81,9 +80,17 @@ class FtrackModule( def connect_with_modules(self, enabled_modules): for module in enabled_modules: - if not isinstance(module, IFtrackEventHandlerPaths): + if not hasattr(module, "get_ftrack_event_handler_paths"): continue - paths_by_type = module.get_event_handler_paths() or {} + + try: + paths_by_type = module.get_ftrack_event_handler_paths() + except Exception: + continue + + if not isinstance(paths_by_type, dict): + continue + for key, value in paths_by_type.items(): if not value: continue diff --git a/openpype/modules/default_modules/ftrack/interfaces.py b/openpype/modules/default_modules/ftrack/interfaces.py deleted file mode 100644 index 16ce0d2e62..0000000000 --- a/openpype/modules/default_modules/ftrack/interfaces.py +++ /dev/null @@ -1,12 +0,0 @@ -from abc import abstractmethod -from openpype.modules import OpenPypeInterface - - -class IFtrackEventHandlerPaths(OpenPypeInterface): - """Other modules interface to return paths to ftrack event handlers. - - Expected output is dictionary with "server" and "user" keys. - """ - @abstractmethod - def get_event_handler_paths(self): - pass diff --git a/openpype/modules/default_modules/ftrack/lib/__init__.py b/openpype/modules/default_modules/ftrack/lib/__init__.py index 9dc2d67279..433a1f7881 100644 --- a/openpype/modules/default_modules/ftrack/lib/__init__.py +++ b/openpype/modules/default_modules/ftrack/lib/__init__.py @@ -5,8 +5,7 @@ from .constants import ( CUST_ATTR_TOOLS, CUST_ATTR_APPLICATIONS ) -from . settings import ( - get_ftrack_url_from_settings, +from .settings import ( get_ftrack_event_mongo_info ) from .custom_attributes import ( @@ -31,7 +30,6 @@ __all__ = ( "CUST_ATTR_TOOLS", "CUST_ATTR_APPLICATIONS", - "get_ftrack_url_from_settings", "get_ftrack_event_mongo_info", "default_custom_attributes_definition", diff --git a/openpype/modules/default_modules/ftrack/lib/settings.py b/openpype/modules/default_modules/ftrack/lib/settings.py index 027356edc6..bf44981de0 100644 --- a/openpype/modules/default_modules/ftrack/lib/settings.py +++ b/openpype/modules/default_modules/ftrack/lib/settings.py @@ -1,13 +1,4 @@ import os -from openpype.api import get_system_settings - - -def get_ftrack_settings(): - return get_system_settings()["modules"]["ftrack"] - - -def get_ftrack_url_from_settings(): - return get_ftrack_settings()["ftrack_server"] def get_ftrack_event_mongo_info(): diff --git a/openpype/modules/default_modules/timers_manager/timers_manager.py b/openpype/modules/default_modules/timers_manager/timers_manager.py index e2c421bcfe..47ba0b4059 100644 --- a/openpype/modules/default_modules/timers_manager/timers_manager.py +++ b/openpype/modules/default_modules/timers_manager/timers_manager.py @@ -209,7 +209,7 @@ class TimersManager(OpenPypeModule, ITrayService, IIdleManager): self.widget_user_idle.refresh_context() self.is_running = False - self.timer_stopper(None) + self.timer_stopped(None) def connect_with_modules(self, enabled_modules): for module in enabled_modules: diff --git a/openpype/plugins/publish/collect_hierarchy.py b/openpype/plugins/publish/collect_hierarchy.py index 1aa10fcb9b..f7d1c6b4be 100644 --- a/openpype/plugins/publish/collect_hierarchy.py +++ b/openpype/plugins/publish/collect_hierarchy.py @@ -13,7 +13,7 @@ class CollectHierarchy(pyblish.api.ContextPlugin): """ label = "Collect Hierarchy" - order = pyblish.api.CollectorOrder - 0.57 + order = pyblish.api.CollectorOrder - 0.47 families = ["shot"] hosts = ["resolve", "hiero"] diff --git a/openpype/plugins/publish/collect_otio_frame_ranges.py b/openpype/plugins/publish/collect_otio_frame_ranges.py index e1b8b95a46..a35ef47e79 100644 --- a/openpype/plugins/publish/collect_otio_frame_ranges.py +++ b/openpype/plugins/publish/collect_otio_frame_ranges.py @@ -18,7 +18,7 @@ class CollectOcioFrameRanges(pyblish.api.InstancePlugin): Adding timeline and source ranges to instance data""" label = "Collect OTIO Frame Ranges" - order = pyblish.api.CollectorOrder - 0.58 + order = pyblish.api.CollectorOrder - 0.48 families = ["shot", "clip"] hosts = ["resolve", "hiero"] diff --git a/openpype/plugins/publish/collect_otio_review.py b/openpype/plugins/publish/collect_otio_review.py index e78ccc032c..10ceafdcca 100644 --- a/openpype/plugins/publish/collect_otio_review.py +++ b/openpype/plugins/publish/collect_otio_review.py @@ -20,7 +20,7 @@ class CollectOcioReview(pyblish.api.InstancePlugin): """Get matching otio track from defined review layer""" label = "Collect OTIO Review" - order = pyblish.api.CollectorOrder - 0.57 + order = pyblish.api.CollectorOrder - 0.47 families = ["clip"] hosts = ["resolve", "hiero"] diff --git a/openpype/plugins/publish/collect_otio_subset_resources.py b/openpype/plugins/publish/collect_otio_subset_resources.py index 010430a303..dd670ff850 100644 --- a/openpype/plugins/publish/collect_otio_subset_resources.py +++ b/openpype/plugins/publish/collect_otio_subset_resources.py @@ -18,7 +18,7 @@ class CollectOcioSubsetResources(pyblish.api.InstancePlugin): """Get Resources for a subset version""" label = "Collect OTIO Subset Resources" - order = pyblish.api.CollectorOrder - 0.57 + order = pyblish.api.CollectorOrder - 0.47 families = ["clip"] hosts = ["resolve", "hiero"] diff --git a/openpype/plugins/publish/validate_ffmpeg_installed.py b/openpype/plugins/publish/validate_ffmpeg_installed.py deleted file mode 100644 index a5390a07b2..0000000000 --- a/openpype/plugins/publish/validate_ffmpeg_installed.py +++ /dev/null @@ -1,34 +0,0 @@ -import pyblish.api -import os -import subprocess -import openpype.lib -try: - import os.errno as errno -except ImportError: - import errno - - -class ValidateFFmpegInstalled(pyblish.api.ContextPlugin): - """Validate availability of ffmpeg tool in PATH""" - - order = pyblish.api.ValidatorOrder - label = 'Validate ffmpeg installation' - optional = True - - def is_tool(self, name): - try: - devnull = open(os.devnull, "w") - subprocess.Popen( - [name], stdout=devnull, stderr=devnull - ).communicate() - except OSError as e: - if e.errno == errno.ENOENT: - return False - return True - - def process(self, context): - ffmpeg_path = openpype.lib.get_ffmpeg_tool_path("ffmpeg") - self.log.info("ffmpeg path: `{}`".format(ffmpeg_path)) - if self.is_tool("{}".format(ffmpeg_path)) is False: - self.log.error("ffmpeg not found in PATH") - raise RuntimeError('ffmpeg not installed.') diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index c215bea2e9..ac35349415 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -102,6 +102,11 @@ }, "ExtractSlateFrame": { "viewer_lut_raw": false + }, + "IncrementScriptVersion": { + "enabled": true, + "optional": true, + "active": true } }, "load": { diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json index 2772c5f3a6..c73453f8aa 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json @@ -173,6 +173,38 @@ "label": "Viewer LUT raw" } ] + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Integrators" + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "IncrementScriptVersion", + "label": "IncrementScriptVersion", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] } ] } diff --git a/openpype/tools/project_manager/project_manager/window.py b/openpype/tools/project_manager/project_manager/window.py index 4a23649ef3..79eb9651e9 100644 --- a/openpype/tools/project_manager/project_manager/window.py +++ b/openpype/tools/project_manager/project_manager/window.py @@ -15,6 +15,11 @@ from openpype.lib import is_admin_password_required from openpype.widgets import PasswordDialog from openpype import resources +from openpype.api import ( + get_project_basic_paths, + create_project_folders, + Logger +) from avalon.api import AvalonMongoDB @@ -24,10 +29,15 @@ class ProjectManagerWindow(QtWidgets.QWidget): def __init__(self, parent=None): super(ProjectManagerWindow, self).__init__(parent) + self.log = Logger.get_logger(self.__class__.__name__) + self._initial_reset = False self._password_dialog = None self._user_passed = False + # keep track of the current project PM is viewing + self._current_project = None + self.setWindowTitle("OpenPype Project Manager") self.setWindowIcon(QtGui.QIcon(resources.get_openpype_icon_filepath())) @@ -57,12 +67,18 @@ class ProjectManagerWindow(QtWidgets.QWidget): create_project_btn = QtWidgets.QPushButton( "Create project...", project_widget ) + create_folders_btn = QtWidgets.QPushButton( + ResourceCache.get_icon("asset", "default"), + "Create Starting Folders", + project_widget + ) project_layout = QtWidgets.QHBoxLayout(project_widget) project_layout.setContentsMargins(0, 0, 0, 0) project_layout.addWidget(project_combobox, 0) project_layout.addWidget(refresh_projects_btn, 0) project_layout.addWidget(create_project_btn, 0) + project_layout.addWidget(create_folders_btn) project_layout.addStretch(1) # Helper buttons @@ -124,6 +140,7 @@ class ProjectManagerWindow(QtWidgets.QWidget): refresh_projects_btn.clicked.connect(self._on_project_refresh) create_project_btn.clicked.connect(self._on_project_create) + create_folders_btn.clicked.connect(self._on_create_folders) project_combobox.currentIndexChanged.connect(self._on_project_change) save_btn.clicked.connect(self._on_save_click) add_asset_btn.clicked.connect(self._on_add_asset) @@ -139,6 +156,7 @@ class ProjectManagerWindow(QtWidgets.QWidget): self._refresh_projects_btn = refresh_projects_btn self._project_combobox = project_combobox self._create_project_btn = create_project_btn + self._create_folders_btn = create_folders_btn self._add_asset_btn = add_asset_btn self._add_task_btn = add_task_btn @@ -179,7 +197,9 @@ class ProjectManagerWindow(QtWidgets.QWidget): self._set_project(self._project_combobox.currentText()) def _on_project_change(self): - self._set_project(self._project_combobox.currentText()) + if self._project_combobox.currentIndex() != 0: + self._current_project = self._project_combobox.currentText() + self._set_project(self._current_project) def _on_project_refresh(self): self.refresh_projects() @@ -193,6 +213,29 @@ class ProjectManagerWindow(QtWidgets.QWidget): def _on_add_task(self): self.hierarchy_view.add_task() + def _on_create_folders(self): + if not self._current_project: + return + + qm = QtWidgets.QMessageBox + ans = qm.question(self, + "OpenPype Project Manager", + "Confirm to create starting project folders?", + qm.Yes | qm.No) + if ans == qm.Yes: + try: + # Get paths based on presets + basic_paths = get_project_basic_paths(self._current_project) + if not basic_paths: + pass + # Invoking OpenPype API to create the project folders + create_project_folders(basic_paths, self._current_project) + except Exception as exc: + self.log.warning( + "Cannot create starting folders: {}".format(exc), + exc_info=True + ) + def show_message(self, message): # TODO add nicer message pop self.message_label.setText(message) @@ -203,9 +246,11 @@ class ProjectManagerWindow(QtWidgets.QWidget): if dialog.result() != 1: return - project_name = dialog.project_name - self.show_message("Created project \"{}\"".format(project_name)) - self.refresh_projects(project_name) + self._current_project = dialog.project_name + self.show_message( + "Created project \"{}\"".format(self._current_project) + ) + self.refresh_projects(self._current_project) def _show_password_dialog(self): if self._password_dialog: diff --git a/start.py b/start.py index 00f9a50cbb..f3adabd942 100644 --- a/start.py +++ b/start.py @@ -96,6 +96,7 @@ Attributes: import os import re import sys +import platform import traceback import subprocess import site @@ -339,6 +340,80 @@ def set_modules_environments(): os.environ.update(env) +def is_tool(name): + try: + import os.errno as errno + except ImportError: + import errno + + try: + devnull = open(os.devnull, "w") + subprocess.Popen( + [name], stdout=devnull, stderr=devnull + ).communicate() + except OSError as exc: + if exc.errno == errno.ENOENT: + return False + return True + + +def _startup_validations(): + """Validations before OpenPype starts.""" + try: + _validate_thirdparty_binaries() + except Exception as exc: + if os.environ.get("OPENPYPE_HEADLESS_MODE"): + raise + + import tkinter + from tkinter.messagebox import showerror + + root = tkinter.Tk() + root.attributes("-alpha", 0.0) + root.wm_state("iconic") + if platform.system().lower() != "windows": + root.withdraw() + + showerror( + "Startup validations didn't pass", + str(exc) + ) + root.withdraw() + sys.exit(1) + + +def _validate_thirdparty_binaries(): + """Check existence of thirdpart executables.""" + low_platform = platform.system().lower() + binary_vendors_dir = os.path.join( + os.environ["OPENPYPE_ROOT"], + "vendor", + "bin" + ) + + error_msg = ( + "Missing binary dependency {}. Please fetch thirdparty dependencies." + ) + # Validate existence of FFmpeg + ffmpeg_dir = os.path.join(binary_vendors_dir, "ffmpeg", low_platform) + if low_platform == "windows": + ffmpeg_dir = os.path.join(ffmpeg_dir, "bin") + ffmpeg_executable = os.path.join(ffmpeg_dir, "ffmpeg") + if not is_tool(ffmpeg_executable): + raise RuntimeError(error_msg.format("FFmpeg")) + + # Validate existence of OpenImageIO (not on MacOs) + if low_platform != "darwin": + oiio_tool_path = os.path.join( + binary_vendors_dir, + "oiio", + low_platform, + "oiiotool" + ) + if not is_tool(oiio_tool_path): + raise RuntimeError(error_msg.format("OpenImageIO")) + + def _process_arguments() -> tuple: """Process command line arguments. @@ -767,6 +842,11 @@ def boot(): # ------------------------------------------------------------------------ os.environ["OPENPYPE_ROOT"] = OPENPYPE_ROOT + # ------------------------------------------------------------------------ + # Do necessary startup validations + # ------------------------------------------------------------------------ + _startup_validations() + # ------------------------------------------------------------------------ # Play animation # ------------------------------------------------------------------------ diff --git a/website/yarn.lock b/website/yarn.lock index b4c12edeb6..066d156d97 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -6594,9 +6594,9 @@ prism-react-renderer@^1.1.1: integrity sha512-GHqzxLYImx1iKN1jJURcuRoA/0ygCcNhfGw1IT8nPIMzarmKQ3Nc+JcG0gi8JXQzuh0C5ShE4npMIoqNin40hg== prismjs@^1.23.0: - version "1.24.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.24.0.tgz#0409c30068a6c52c89ef7f1089b3ca4de56be2ac" - integrity sha512-SqV5GRsNqnzCL8k5dfAjCNhUrF3pR0A9lTDSCUZeh/LIshheXJEaP0hwLz2t4XHivd2J/v2HR+gRnigzeKe3cQ== + version "1.25.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" + integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== process-nextick-args@~2.0.0: version "2.0.1"