From 89957fca966bc95976420240117377d729fb26de Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Jul 2021 13:59:00 +0200 Subject: [PATCH 01/12] check_inventory_versions skip representations that were not found in database --- openpype/hosts/nuke/api/lib.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index d7f3fdc6ba..9922409dd1 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -113,6 +113,14 @@ def check_inventory_versions(): "_id": io.ObjectId(avalon_knob_data["representation"]) }) + # Failsafe for not finding the representation. + if not representation: + log.warning( + "Could not find the representation on " + "node \"{}\"".format(node.name()) + ) + continue + # Get start frame from version data version = io.find_one({ "type": "version", From 570aa35269c37c3291985e9e38ad7cab57f986f3 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 14 Jul 2021 11:55:00 +0200 Subject: [PATCH 02/12] add support for pyenv-win on windows --- tools/build.ps1 | 6 +++++- tools/create_env.ps1 | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tools/build.ps1 b/tools/build.ps1 index cc4253fe24..e1962ee933 100644 --- a/tools/build.ps1 +++ b/tools/build.ps1 @@ -83,8 +83,12 @@ function Show-PSWarning() { function Install-Poetry() { Write-Host ">>> " -NoNewline -ForegroundColor Green Write-Host "Installing Poetry ... " + $python = "python" + if (Get-Command "pyenv" -ErrorAction SilentlyContinue) { + $python = & pyenv which python + } $env:POETRY_HOME="$openpype_root\.poetry" - (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | python - + (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | & $($python) - } $art = @" diff --git a/tools/create_env.ps1 b/tools/create_env.ps1 index 6c8124ccb2..2ab6abe76e 100644 --- a/tools/create_env.ps1 +++ b/tools/create_env.ps1 @@ -48,15 +48,23 @@ function Show-PSWarning() { function Install-Poetry() { Write-Host ">>> " -NoNewline -ForegroundColor Green Write-Host "Installing Poetry ... " + $python = "python" + if (Get-Command "pyenv" -ErrorAction SilentlyContinue) { + $python = & pyenv which python + } $env:POETRY_HOME="$openpype_root\.poetry" - (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | python - + (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | & $($python) - } function Test-Python() { Write-Host ">>> " -NoNewline -ForegroundColor green Write-Host "Detecting host Python ... " -NoNewline - if (-not (Get-Command "python" -ErrorAction SilentlyContinue)) { + $python = "python" + if (Get-Command "pyenv" -ErrorAction SilentlyContinue) { + $python = & pyenv which python + } + if (-not (Get-Command "python3" -ErrorAction SilentlyContinue)) { Write-Host "!!! Python not detected" -ForegroundColor red Set-Location -Path $current_dir Exit-WithCode 1 @@ -66,7 +74,7 @@ import sys print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1])) '@ - $p = & python -c $version_command + $p = & $python -c $version_command $env:PYTHON_VERSION = $p $m = $p -match '(\d+)\.(\d+)' if(-not $m) { From ae13ab38eb48814a629d47efec5cfb7ff65bc028 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 14 Jul 2021 14:19:55 +0200 Subject: [PATCH 03/12] add support to select preferred mongo version on windows --- tools/run_mongo.ps1 | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/tools/run_mongo.ps1 b/tools/run_mongo.ps1 index 6719e520fe..32f6cfed17 100644 --- a/tools/run_mongo.ps1 +++ b/tools/run_mongo.ps1 @@ -41,22 +41,40 @@ function Exit-WithCode($exitcode) { } -function Find-Mongo { +function Find-Mongo ($preferred_version) { $defaultPath = "C:\Program Files\MongoDB\Server" Write-Host ">>> " -NoNewLine -ForegroundColor Green Write-Host "Detecting MongoDB ... " -NoNewline if (-not (Get-Command "mongod" -ErrorAction SilentlyContinue)) { if(Test-Path "$($defaultPath)\*\bin\mongod.exe" -PathType Leaf) { # we have mongo server installed on standard Windows location - # so we can inject it to the PATH. We'll use latest version available. + # so we can inject it to the PATH. We'll use latest version available, or the one defined by + # $preferred_version. $mongoVersions = Get-ChildItem -Directory 'C:\Program Files\MongoDB\Server' | Sort-Object -Property {$_.Name -as [int]} if(Test-Path "$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) { - $env:PATH = "$($env:PATH);$($mongoVersions[-1])\bin\" Write-Host "OK" -ForegroundColor Green + $use_version = $mongoVersions[-1] + foreach ($v in $mongoVersions) { + Write-Host " - found [ " -NoNewline + Write-Host $v -NoNewLine -ForegroundColor Cyan + Write-Host " ]" -NoNewLine + + $version = Split-Path $v -Leaf + + if ($preferred_version -eq $version) { + Write-Host " *" -ForegroundColor Green + $use_version = $v + } else { + Write-Host "" + } + } + + $env:PATH = "$($env:PATH);$($use_version)\bin\" + Write-Host " - auto-added from [ " -NoNewline - Write-Host "$($mongoVersions[-1])\bin\mongod.exe" -NoNewLine -ForegroundColor Cyan + Write-Host "$($use_version)\bin\mongod.exe" -NoNewLine -ForegroundColor Cyan Write-Host " ]" - return "$($mongoVersions[-1])\bin\mongod.exe" + return "$($use_version)\bin\mongod.exe" } else { Write-Host "FAILED " -NoNewLine -ForegroundColor Red Write-Host "MongoDB not detected" -ForegroundColor Yellow @@ -95,7 +113,18 @@ $port = 2707 # path to database $dbpath = (Get-Item $openpype_root).parent.FullName + "\mongo_db_data" -$mongoPath = Find-Mongo -Start-Process -FilePath $mongopath "--dbpath $($dbpath) --port $($port)" -PassThru +$preferred_version = "4.0" +$mongoPath = Find-Mongo $preferred_version +Write-Host ">>> " -NoNewLine -ForegroundColor Green +Write-Host "Using DB path: " -NoNewLine +Write-Host " [ " -NoNewline -ForegroundColor Cyan +Write-Host "$($dbpath)" -NoNewline -ForegroundColor White +Write-Host " ] "-ForegroundColor Cyan +Write-Host ">>> " -NoNewLine -ForegroundColor Green +Write-Host "Port: " -NoNewLine +Write-Host " [ " -NoNewline -ForegroundColor Cyan +Write-Host "$($port)" -NoNewline -ForegroundColor White +Write-Host " ] " -ForegroundColor Cyan +Start-Process -FilePath $mongopath "--dbpath $($dbpath) --port $($port)" -PassThru | Out-Null From b6e28c19b4475e7b0c0f03954a8cf9cf4f80730c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 20 Jul 2021 13:54:25 +0200 Subject: [PATCH 04/12] Nuke: fixing loading and updating effects --- openpype/hosts/nuke/plugins/load/load_effects.py | 2 +- .../hosts/nuke/plugins/load/load_effects_ip.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/nuke/plugins/load/load_effects.py b/openpype/hosts/nuke/plugins/load/load_effects.py index 6306767f37..8ba1b6b7c1 100644 --- a/openpype/hosts/nuke/plugins/load/load_effects.py +++ b/openpype/hosts/nuke/plugins/load/load_effects.py @@ -214,7 +214,7 @@ class LoadEffects(api.Loader): self.log.warning(e) continue - if isinstance(v, list) and len(v) > 3: + if isinstance(v, list) and len(v) > 4: node[k].setAnimated() for i, value in enumerate(v): if isinstance(value, list): diff --git a/openpype/hosts/nuke/plugins/load/load_effects_ip.py b/openpype/hosts/nuke/plugins/load/load_effects_ip.py index 6c71f2ae16..d0cab26842 100644 --- a/openpype/hosts/nuke/plugins/load/load_effects_ip.py +++ b/openpype/hosts/nuke/plugins/load/load_effects_ip.py @@ -217,7 +217,7 @@ class LoadEffectsInputProcess(api.Loader): self.log.warning(e) continue - if isinstance(v, list) and len(v) > 3: + if isinstance(v, list) and len(v) > 4: node[k].setAnimated() for i, value in enumerate(v): if isinstance(value, list): @@ -239,10 +239,10 @@ class LoadEffectsInputProcess(api.Loader): output = nuke.createNode("Output") output.setInput(0, pre_node) - # try to place it under Viewer1 - if not self.connect_active_viewer(GN): - nuke.delete(GN) - return + # # try to place it under Viewer1 + # if not self.connect_active_viewer(GN): + # nuke.delete(GN) + # return # get all versions in list versions = io.find({ @@ -298,7 +298,11 @@ class LoadEffectsInputProcess(api.Loader): viewer["input_process_node"].setValue(group_node_name) # put backdrop under - lib.create_backdrop(label="Input Process", layer=2, nodes=[viewer, group_node], color="0x7c7faaff") + lib.create_backdrop( + label="Input Process", + layer=2, + nodes=[viewer, group_node], + color="0x7c7faaff") return True From 246a3cff52f0f4d6bd69aff4dafc44260f01d7de Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 20 Jul 2021 18:05:17 +0200 Subject: [PATCH 05/12] create the project in avalon if does not exist yet --- .../action_prepare_project.py | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py b/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py index 5298c06371..e9b0b2a58a 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py +++ b/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py @@ -1,6 +1,8 @@ import json +from avalon.api import AvalonMongoDB from openpype.api import ProjectSettings +from openpype.lib import create_project from openpype.modules.ftrack.lib import ( BaseAction, @@ -48,13 +50,22 @@ class PrepareProjectLocal(BaseAction): project_entity = entities[0] project_name = project_entity["full_name"] - try: - project_settings = ProjectSettings(project_name) - except ValueError: - return { - "message": "Project is not synchronized yet", - "success": False - } + # Try to find project document + dbcon = AvalonMongoDB() + dbcon.install() + dbcon.Session["AVALON_PROJECT"] = project_name + project_doc = dbcon.find_one({ + "type": "project" + }) + # Create project if is not available + # - creation is required to be able set project anatomy and attributes + if not project_doc: + project_code = project_entity["name"] + create_project(project_name, project_code, dbcon=dbcon) + + dbcon.uninstall() + + project_settings = ProjectSettings(project_name) project_anatom_settings = project_settings["project_anatomy"] root_items = self.prepare_root_items(project_anatom_settings) From 0e38083a014446acc56e0043d67e0f25914d96e9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 20 Jul 2021 18:05:27 +0200 Subject: [PATCH 06/12] add basic order of attributes --- .../action_prepare_project.py | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py b/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py index e9b0b2a58a..4bcd058ca8 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py +++ b/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py @@ -26,6 +26,21 @@ class PrepareProjectLocal(BaseAction): # Key to store info about trigerring create folder structure item_splitter = {"type": "label", "value": "---"} + _keys_order = ( + "fps", + "frameStart", + "frameEnd", + "handleStart", + "handleEnd", + "clipIn", + "clipOut", + "resolutionHeight", + "resolutionWidth", + "pixelAspect", + "applications", + "tools_env", + "library_project", + ) def discover(self, session, entities, event): """Show only on project.""" @@ -211,7 +226,18 @@ class PrepareProjectLocal(BaseAction): str([key for key in attributes_to_set]) )) - for key, in_data in attributes_to_set.items(): + attribute_keys = set(attributes_to_set.keys()) + keys_order = [] + for key in self._keys_order: + if key in attribute_keys: + keys_order.append(key) + + attribute_keys = attribute_keys - set(keys_order) + for key in sorted(attribute_keys): + keys_order.append(key) + + for key in keys_order: + in_data = attributes_to_set[key] attr = in_data["object"] # initial item definition From 1f4c644fc0aab6d64d34762c799bfad34a13b3b4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 20 Jul 2021 18:28:56 +0200 Subject: [PATCH 07/12] create project when values are confirmed, not before --- .../action_prepare_project.py | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py b/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py index 4bcd058ca8..5c40ec0d30 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py +++ b/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py @@ -65,21 +65,6 @@ class PrepareProjectLocal(BaseAction): project_entity = entities[0] project_name = project_entity["full_name"] - # Try to find project document - dbcon = AvalonMongoDB() - dbcon.install() - dbcon.Session["AVALON_PROJECT"] = project_name - project_doc = dbcon.find_one({ - "type": "project" - }) - # Create project if is not available - # - creation is required to be able set project anatomy and attributes - if not project_doc: - project_code = project_entity["name"] - create_project(project_name, project_code, dbcon=dbcon) - - dbcon.uninstall() - project_settings = ProjectSettings(project_name) project_anatom_settings = project_settings["project_anatomy"] @@ -375,7 +360,27 @@ class PrepareProjectLocal(BaseAction): self.log.debug("Setting Custom Attribute values") - project_name = entities[0]["full_name"] + project_entity = entities[0] + project_name = project_entity["full_name"] + + # Try to find project document + dbcon = AvalonMongoDB() + dbcon.install() + dbcon.Session["AVALON_PROJECT"] = project_name + project_doc = dbcon.find_one({ + "type": "project" + }) + # Create project if is not available + # - creation is required to be able set project anatomy and attributes + if not project_doc: + project_code = project_entity["name"] + self.log.info("Creating project \"{} [{}]\"".format( + project_name, project_code + )) + create_project(project_name, project_code, dbcon=dbcon) + + dbcon.uninstall() + project_settings = ProjectSettings(project_name) project_anatomy_settings = project_settings["project_anatomy"] project_anatomy_settings["roots"] = root_data From 8b3aeddaa7cee1383fad72192c3f3308fa97010a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 21 Jul 2021 17:33:00 +0200 Subject: [PATCH 08/12] added usefull methods to add traceback to job in ftrack base event handler --- .../modules/ftrack/lib/ftrack_base_handler.py | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/openpype/modules/ftrack/lib/ftrack_base_handler.py b/openpype/modules/ftrack/lib/ftrack_base_handler.py index 817841df4a..ba8b065d34 100644 --- a/openpype/modules/ftrack/lib/ftrack_base_handler.py +++ b/openpype/modules/ftrack/lib/ftrack_base_handler.py @@ -1,4 +1,10 @@ +import os +import sys +import tempfile +import json import functools +import datetime +import traceback import time from openpype.api import Logger from openpype.settings import get_project_settings @@ -583,3 +589,105 @@ class BaseHandler(object): return "/".join( [ent["name"] for ent in entity["link"]] ) + + @classmethod + def add_traceback_to_job( + cls, job, session, exc_info, + description=None, + component_name=None, + job_status=None + ): + """Add traceback file to a job. + + Args: + job (JobEntity): Entity of job where file should be able to + download (Created or queried with passed session). + session (Session): Ftrack session which was used to query/create + entered job. + exc_info (tuple): Exception info (e.g. from `sys.exc_info()`). + description (str): Change job description to describe what + happened. Job description won't change if not passed. + component_name (str): Name of component and default name of + downloaded file. Class name and current date time are used if + not specified. + job_status (str): Status of job which will be set. By default is + set to 'failed'. + """ + if description: + job_data = { + "description": description + } + job["data"] = json.dumps(job_data) + + if not job_status: + job_status = "failed" + + job["status"] = job_status + + # Create temp file where traceback will be stored + temp_obj = tempfile.NamedTemporaryFile( + mode="w", prefix="openpype_ftrack_", suffix=".txt", delete=False + ) + temp_obj.close() + temp_filepath = temp_obj.name + + # Store traceback to file + result = traceback.format_exception(*exc_info) + with open(temp_filepath, "w") as temp_file: + temp_file.write("".join(result)) + + # Upload file with traceback to ftrack server and add it to job + if not component_name: + component_name = "{}_{}".format( + cls.__name__, + datetime.datetime.now().strftime("%y-%m-%d-%H%M") + ) + cls.add_component_to_job( + job, session, temp_filepath, component_name + ) + # Delete temp file + os.remove(temp_filepath) + + @staticmethod + def add_file_component_to_job(job, session, filepath, basename=None): + """Add filepath as downloadable component to job. + + Args: + job (JobEntity): Entity of job where file should be able to + download (Created or queried with passed session). + session (Session): Ftrack session which was used to query/create + entered job. + filepath (str): Path to file which should be added to job. + basename (str): Defines name of file which will be downloaded on + user's side. Must be without extension otherwise extension will + be duplicated in downloaded name. Basename from entered path + used when not entered. + """ + # Make sure session's locations are configured + # - they can be deconfigured e.g. using `rollback` method + session._configure_locations() + + # Query `ftrack.server` location where component will be stored + location = session.query( + "Location where name is \"ftrack.server\"" + ).one() + + # Use filename as basename if not entered (must be without extension) + if basename is None: + basename = os.path.splitext( + os.path.basename(filepath) + )[0] + + component = session.create_component( + filepath, + data={"name": basename}, + location=location + ) + session.create( + "JobComponent", + { + "component_id": component["id"], + "job_id": job["id"] + } + ) + session.commit() From 3f1305b88f88cdf88db068009b5f9e50bf19122c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 21 Jul 2021 17:35:24 +0200 Subject: [PATCH 09/12] use add_traceback_to_job from base event handler to store traceback to a job --- .../action_push_frame_values_to_task.py | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_server/action_push_frame_values_to_task.py b/openpype/modules/ftrack/event_handlers_server/action_push_frame_values_to_task.py index 214f1ecf18..255ec252c2 100644 --- a/openpype/modules/ftrack/event_handlers_server/action_push_frame_values_to_task.py +++ b/openpype/modules/ftrack/event_handlers_server/action_push_frame_values_to_task.py @@ -1,3 +1,4 @@ +import sys import json import collections import ftrack_api @@ -90,27 +91,28 @@ class PushHierValuesToNonHier(ServerAction): try: result = self.propagate_values(session, event, entities) - job["status"] = "done" - session.commit() - - return result - - except Exception: - session.rollback() - job["status"] = "failed" - session.commit() + except Exception as exc: msg = "Pushing Custom attribute values to task Failed" + self.log.warning(msg, exc_info=True) + + session.rollback() + + description = "{} (Download traceback)".format(msg) + self.add_traceback_to_job( + job, session, sys.exc_info(), event, description + ) + return { "success": False, - "message": msg + "message": "Error: {}".format(str(exc)) } - finally: - if job["status"] == "running": - job["status"] = "failed" - session.commit() + job["status"] = "done" + session.commit() + + return result def attrs_configurations(self, session, object_ids, interest_attributes): attrs = session.query(self.cust_attrs_query.format( From d5c4009935f7021568f58c0f2ed1290184469a5f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 21 Jul 2021 17:37:55 +0200 Subject: [PATCH 10/12] removed unused import --- openpype/modules/ftrack/lib/ftrack_base_handler.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/modules/ftrack/lib/ftrack_base_handler.py b/openpype/modules/ftrack/lib/ftrack_base_handler.py index ba8b065d34..c56412421f 100644 --- a/openpype/modules/ftrack/lib/ftrack_base_handler.py +++ b/openpype/modules/ftrack/lib/ftrack_base_handler.py @@ -1,5 +1,4 @@ import os -import sys import tempfile import json import functools From d96998626a70c300d20657288893ca86e358dc06 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 21 Jul 2021 17:44:02 +0200 Subject: [PATCH 11/12] fix method name --- openpype/modules/ftrack/lib/ftrack_base_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/lib/ftrack_base_handler.py b/openpype/modules/ftrack/lib/ftrack_base_handler.py index c56412421f..011ce8db9d 100644 --- a/openpype/modules/ftrack/lib/ftrack_base_handler.py +++ b/openpype/modules/ftrack/lib/ftrack_base_handler.py @@ -641,7 +641,7 @@ class BaseHandler(object): cls.__name__, datetime.datetime.now().strftime("%y-%m-%d-%H%M") ) - cls.add_component_to_job( + cls.add_file_component_to_job( job, session, temp_filepath, component_name ) # Delete temp file From c7dc3ac1015d841ea328e390b60fc7e3dfb0e827 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 21 Jul 2021 17:44:21 +0200 Subject: [PATCH 12/12] fix args --- .../event_handlers_server/action_push_frame_values_to_task.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/event_handlers_server/action_push_frame_values_to_task.py b/openpype/modules/ftrack/event_handlers_server/action_push_frame_values_to_task.py index 255ec252c2..b38e18d089 100644 --- a/openpype/modules/ftrack/event_handlers_server/action_push_frame_values_to_task.py +++ b/openpype/modules/ftrack/event_handlers_server/action_push_frame_values_to_task.py @@ -101,7 +101,7 @@ class PushHierValuesToNonHier(ServerAction): description = "{} (Download traceback)".format(msg) self.add_traceback_to_job( - job, session, sys.exc_info(), event, description + job, session, sys.exc_info(), description ) return {