From 70948555e00c8a4677e82b24e623a3a524c0d5f2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Sep 2022 21:33:57 +0200 Subject: [PATCH 001/211] nuke: adding pipeline abstraction for new publisher --- openpype/hosts/nuke/api/__init__.py | 8 ++++ openpype/hosts/nuke/api/pipeline.py | 63 ++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 962f31c177..42b669fec3 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -18,6 +18,10 @@ from .pipeline import ( ls, + list_instances, + remove_instance, + select_instance, + containerise, parse_container, update_container, @@ -51,6 +55,10 @@ __all__ = ( "ls", + "list_instances", + "remove_instance", + "select_instance", + "containerise", "parse_container", "update_container", diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index bac42128cc..50e7dd9495 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -39,6 +39,7 @@ from .lib import ( check_inventory_versions, set_avalon_knob_data, read_avalon_data, + get_avalon_knob_data ) from .lib_template_builder import ( create_placeholder, update_placeholder @@ -431,7 +432,6 @@ def ls(): """ all_nodes = nuke.allNodes(recurseGroups=False) - # TODO: add readgeo, readcamera, readimage nodes = [n for n in all_nodes] for n in nodes: @@ -439,3 +439,64 @@ def ls(): container = parse_container(n) if container: yield container + + +def list_instances(): + """List all created instances to publish from current workfile. + + For SubsetManager + + Returns: + (list) of dictionaries matching instances format + """ + instances = [] + for node in nuke.allNodes(): + + if node.Class() in ["Viewer", "Dot"]: + continue + + try: + if node["disable"].value(): + continue + except Exception as E: + log.warning(E) + + # get data from avalon knob + avalon_knob_data = get_avalon_knob_data( + node, ["avalon:", "ak:"]) + + if not avalon_knob_data: + continue + + if avalon_knob_data["id"] != "pyblish.avalon.instance": + continue + + # add node name + avalon_knob_data["name"] = node.name() + + instances.append(avalon_knob_data) + + return instances + + +def remove_instance(instance): + """Remove instance from current workfile metadata. + + For SubsetManager + + Args: + instance (dict): instance representation from subsetmanager model + """ + node = nuke.toNode(instance["name"]) + nuke.delete(node) + + +def select_instance(instance): + """ + Select instance in Node View + + Args: + instance (dict): instance representation from subsetmanager model + """ + node = nuke.toNode(instance["name"]) + node["selected"].setValue(True) From 8e3eab2f6007f666317f22af2894662568cb7f5f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Sep 2022 21:34:13 +0200 Subject: [PATCH 002/211] nuke: adding workfile creator --- .../nuke/plugins/create/workfile_creator.py | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 openpype/hosts/nuke/plugins/create/workfile_creator.py diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py new file mode 100644 index 0000000000..9ceaf376c1 --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -0,0 +1,77 @@ +import openpype.hosts.nuke.api as api +from openpype.client import get_asset_by_name +from openpype.pipeline import ( + AutoCreator, + CreatedInstance, + legacy_io, +) + + +class WorkfileCreator(AutoCreator): + identifier = "workfile" + family = "workfile" + + default_variant = "Main" + + def get_instance_attr_defs(self): + return [] + + def collect_instances(self): + for instance_data in api.list_instances(): + creator_id = instance_data.get("creator_identifier") + if creator_id == self.identifier: + subset_name = instance_data["subset"] + instance = CreatedInstance( + self.family, subset_name, instance_data, self + ) + self._add_instance_to_context(instance) + + def update_instances(self, update_list): + # nothing to change on workfiles + pass + + def create(self, options=None): + existing_instance = None + for instance in self.create_context.instances: + if instance.family == self.family: + existing_instance = instance + break + + project_name = legacy_io.Session["AVALON_PROJECT"] + asset_name = legacy_io.Session["AVALON_ASSET"] + task_name = legacy_io.Session["AVALON_TASK"] + host_name = legacy_io.Session["AVALON_APP"] + + if existing_instance is None: + asset_doc = get_asset_by_name(project_name, asset_name) + subset_name = self.get_subset_name( + self.default_variant, task_name, asset_doc, + project_name, host_name + ) + data = { + "asset": asset_name, + "task": task_name, + "variant": self.default_variant + } + data.update(self.get_dynamic_data( + self.default_variant, task_name, asset_doc, + project_name, host_name + )) + + new_instance = CreatedInstance( + self.family, subset_name, data, self + ) + self._add_instance_to_context(new_instance) + + elif ( + existing_instance["asset"] != asset_name + or existing_instance["task"] != task_name + ): + asset_doc = get_asset_by_name(project_name, asset_name) + subset_name = self.get_subset_name( + self.default_variant, task_name, asset_doc, + project_name, host_name + ) + existing_instance["asset"] = asset_name + existing_instance["task"] = task_name + existing_instance["subset"] = subset_name From a7caced36e5f5f6184a95f9c0ce7fc30e1666107 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 12:18:50 +0200 Subject: [PATCH 003/211] nuke: refactor host to be NukeHost --- openpype/hosts/nuke/api/__init__.py | 9 +- openpype/hosts/nuke/api/lib.py | 26 +++++ openpype/hosts/nuke/api/pipeline.py | 165 ++++++++++++++++++---------- openpype/hosts/nuke/startup/menu.py | 65 +---------- 4 files changed, 138 insertions(+), 127 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 42b669fec3..38f51a309e 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -6,15 +6,12 @@ from .workio import ( current_file, work_root, ) - from .command import ( viewer_update_and_undo_stop ) - from .plugin import OpenPypeCreator from .pipeline import ( - install, - uninstall, + NukeHost, ls, @@ -33,7 +30,6 @@ from .lib import ( duplicate_node, convert_knob_value_to_correct_type ) - from .utils import ( colorspace_exists_on_node, get_colorspace_list @@ -50,8 +46,7 @@ __all__ = ( "viewer_update_and_undo_stop", "OpenPypeCreator", - "install", - "uninstall", + "NukeHost", "ls", diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index e55fdbfcb2..764e904295 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2605,6 +2605,32 @@ def recreate_instance(origin_node, avalon_data=None): return new_node +def add_scripts_menu(): + try: + from scriptsmenu import launchfornuke + except ImportError: + log.warning( + "Skipping studio.menu install, because " + "'scriptsmenu' module seems unavailable." + ) + return + + # load configuration of custom menu + project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) + config = project_settings["nuke"]["scriptsmenu"]["definition"] + _menu = project_settings["nuke"]["scriptsmenu"]["name"] + + if not config: + log.warning("Skipping studio menu, no definition found.") + return + + # run the launcher for Maya menu + studio_menu = launchfornuke.main(title=_menu.title()) + + # apply configuration + studio_menu.build_from_configuration(studio_menu, config) + + def add_scripts_gizmo(): # load configuration of custom menu diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 50e7dd9495..2301149872 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -1,12 +1,18 @@ +import nuke + import os import importlib from collections import OrderedDict -import nuke - import pyblish.api import openpype +from openpype.host import ( + HostBase, + IWorkfileHost, + ILoadHost, + INewPublisher +) from openpype.api import ( Logger, get_current_project_settings @@ -39,11 +45,23 @@ from .lib import ( check_inventory_versions, set_avalon_knob_data, read_avalon_data, - get_avalon_knob_data + get_avalon_knob_data, + on_script_load, + dirmap_file_name_filter, + add_scripts_menu, + add_scripts_gizmo ) from .lib_template_builder import ( create_placeholder, update_placeholder ) +from .workio import ( + open_file, + save_file, + file_extensions, + has_unsaved_changes, + work_root, + current_file +) log = Logger.get_logger(__name__) @@ -62,6 +80,92 @@ if os.getenv("PYBLISH_GUI", None): pyblish.api.register_gui(os.getenv("PYBLISH_GUI", None)) +class NukeHost( + HostBase, IWorkfileHost, ILoadHost, INewPublisher +): + name = "nuke" + + def open_workfile(self, filepath): + return open_file(filepath) + + def save_workfile(self, filepath=None): + return save_file(filepath) + + def work_root(self, session): + return work_root(session) + + def get_current_workfile(self): + return current_file() + + def workfile_has_unsaved_changes(self): + return has_unsaved_changes() + + def get_workfile_extensions(self): + return file_extensions() + + def get_containers(self): + return ls() + + def install(self): + ''' Installing all requarements for Nuke host + ''' + + pyblish.api.register_host("nuke") + + self.log.info("Registering Nuke plug-ins..") + pyblish.api.register_plugin_path(PUBLISH_PATH) + register_loader_plugin_path(LOAD_PATH) + register_creator_plugin_path(CREATE_PATH) + register_inventory_action_path(INVENTORY_PATH) + + # Register Avalon event for workfiles loading. + register_event_callback("workio.open_file", check_inventory_versions) + register_event_callback("taskChanged", change_context_label) + + pyblish.api.register_callback( + "instanceToggled", on_pyblish_instance_toggled) + + _install_menu() + + # add script menu + add_scripts_menu() + add_scripts_gizmo() + + add_nuke_callbacks() + + launch_workfiles_app() + + def get_context_data(self): + pass + + def update_context_data(self, data, changes): + pass + + +def add_nuke_callbacks(): + + workfile_settings = WorkfileSettings() + # Set context settings. + nuke.addOnCreate( + workfile_settings.set_context_settings, nodeClass="Root") + nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root") + nuke.addOnCreate(process_workfile_builder, nodeClass="Root") + + # fix ffmpeg settings on script + nuke.addOnScriptLoad(on_script_load) + + # set checker for last versions on loaded containers + nuke.addOnScriptLoad(check_inventory_versions) + nuke.addOnScriptSave(check_inventory_versions) + + # # set apply all workfile settings on script load and save + nuke.addOnScriptLoad(WorkfileSettings().set_context_settings) + + nuke.addFilenameFilter(dirmap_file_name_filter) + + log.info('Automatic syncing of write file knob to script version') + + def reload_config(): """Attempt to reload pipeline at run-time. @@ -88,52 +192,6 @@ def reload_config(): reload(module) -def install(): - ''' Installing all requarements for Nuke host - ''' - - pyblish.api.register_host("nuke") - - log.info("Registering Nuke plug-ins..") - pyblish.api.register_plugin_path(PUBLISH_PATH) - register_loader_plugin_path(LOAD_PATH) - register_creator_plugin_path(CREATE_PATH) - register_inventory_action_path(INVENTORY_PATH) - - # Register Avalon event for workfiles loading. - register_event_callback("workio.open_file", check_inventory_versions) - register_event_callback("taskChanged", change_context_label) - - pyblish.api.register_callback( - "instanceToggled", on_pyblish_instance_toggled) - workfile_settings = WorkfileSettings() - - # Set context settings. - nuke.addOnCreate(workfile_settings.set_context_settings, nodeClass="Root") - nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root") - nuke.addOnCreate(process_workfile_builder, nodeClass="Root") - - _install_menu() - launch_workfiles_app() - - -def uninstall(): - '''Uninstalling host's integration - ''' - log.info("Deregistering Nuke plug-ins..") - pyblish.deregister_host("nuke") - pyblish.api.deregister_plugin_path(PUBLISH_PATH) - deregister_loader_plugin_path(LOAD_PATH) - deregister_creator_plugin_path(CREATE_PATH) - deregister_inventory_action_path(INVENTORY_PATH) - - pyblish.api.deregister_callback( - "instanceToggled", on_pyblish_instance_toggled) - - reload_config() - _uninstall_menu() - - def _show_workfiles(): # Make sure parent is not set # - this makes Workfiles tool as separated window which @@ -244,15 +302,6 @@ def _install_menu(): add_shortcuts_from_presets() -def _uninstall_menu(): - menubar = nuke.menu("Nuke") - menu = menubar.findItem(MENU_LABEL) - - for item in menu.items(): - log.info("Removing menu item: {}".format(item.name())) - menu.removeItem(item.name()) - - def change_context_label(): menubar = nuke.menu("Nuke") menu = menubar.findItem(MENU_LABEL) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 1461d41385..613d508387 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,64 +1,5 @@ -import nuke -import os - -from openpype.api import Logger from openpype.pipeline import install_host -from openpype.hosts.nuke import api -from openpype.hosts.nuke.api.lib import ( - on_script_load, - check_inventory_versions, - WorkfileSettings, - dirmap_file_name_filter, - add_scripts_gizmo -) -from openpype.settings import get_project_settings +from openpype.hosts.nuke.api import NukeHost -log = Logger.get_logger(__name__) - - -install_host(api) - -# fix ffmpeg settings on script -nuke.addOnScriptLoad(on_script_load) - -# set checker for last versions on loaded containers -nuke.addOnScriptLoad(check_inventory_versions) -nuke.addOnScriptSave(check_inventory_versions) - -# # set apply all workfile settings on script load and save -nuke.addOnScriptLoad(WorkfileSettings().set_context_settings) - -nuke.addFilenameFilter(dirmap_file_name_filter) - -log.info('Automatic syncing of write file knob to script version') - - -def add_scripts_menu(): - try: - from scriptsmenu import launchfornuke - except ImportError: - log.warning( - "Skipping studio.menu install, because " - "'scriptsmenu' module seems unavailable." - ) - return - - # load configuration of custom menu - project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) - config = project_settings["nuke"]["scriptsmenu"]["definition"] - _menu = project_settings["nuke"]["scriptsmenu"]["name"] - - if not config: - log.warning("Skipping studio menu, no definition found.") - return - - # run the launcher for Maya menu - studio_menu = launchfornuke.main(title=_menu.title()) - - # apply configuration - studio_menu.build_from_configuration(studio_menu, config) - - -add_scripts_menu() - -add_scripts_gizmo() +host = NukeHost() +install_host(host) From 501da09b79fc8bcf54b9abda92714cb5d5eabdd3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 12:23:30 +0200 Subject: [PATCH 004/211] nuke: change log info and removing unused imports --- openpype/hosts/nuke/api/pipeline.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 2301149872..26372d0047 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -22,9 +22,6 @@ from openpype.pipeline import ( register_loader_plugin_path, register_creator_plugin_path, register_inventory_action_path, - deregister_loader_plugin_path, - deregister_creator_plugin_path, - deregister_inventory_action_path, AVALON_CONTAINER_ID, ) from openpype.pipeline.workfile import BuildWorkfile @@ -138,12 +135,13 @@ class NukeHost( def get_context_data(self): pass - def update_context_data(self, data, changes): + def update_context_data(self, data): pass def add_nuke_callbacks(): - + """ Adding all available nuke callbacks + """ workfile_settings = WorkfileSettings() # Set context settings. nuke.addOnCreate( @@ -163,7 +161,7 @@ def add_nuke_callbacks(): nuke.addFilenameFilter(dirmap_file_name_filter) - log.info('Automatic syncing of write file knob to script version') + log.info("Added Nuke callbacks ...") def reload_config(): From 8e1342fd086591f713588fbdc6b4380399d0cfdf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 15:00:35 +0200 Subject: [PATCH 005/211] nuke: menu change to new publisher --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 26372d0047..cfc8fd52b2 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -231,7 +231,7 @@ def _install_menu(): ) menu.addCommand( "Publish...", - lambda: host_tools.show_publish(parent=main_window) + lambda: host_tools.show_publisher(parent=main_window) ) menu.addCommand( "Manage...", From 7a42beb2db9187e9180b75f2cc5a45d8b7081fa9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 15:01:05 +0200 Subject: [PATCH 006/211] nuke: add update/get context data --- openpype/hosts/nuke/api/pipeline.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index cfc8fd52b2..373fd7134b 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -1,6 +1,7 @@ import nuke import os +import json import importlib from collections import OrderedDict @@ -34,6 +35,8 @@ from openpype.tools.utils import host_tools from .command import viewer_update_and_undo_stop from .lib import ( Context, + imprint, + Knobby, get_main_window, add_publish_knob, WorkfileSettings, @@ -133,10 +136,22 @@ class NukeHost( launch_workfiles_app() def get_context_data(self): - pass + root_node = nuke.root() + context_value = root_node["publish_context"].getValue() + return json.loads(context_value) - def update_context_data(self, data): - pass + def update_context_data(self, data, changes): + root_node = nuke.root() + imprint( + root_node, + { + "publish_context": Knobby( + "String_Knob", + json.dumps(data), + flags=[nuke.INVISIBLE] + ) + } + ) def add_nuke_callbacks(): From 9c050d47cba9ca85fb75fdf35f678701a9c77fdf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 22:44:08 +0200 Subject: [PATCH 007/211] nuke: implementing write and read create data functions --- openpype/hosts/nuke/api/lib.py | 100 +++++++++++++--------------- openpype/hosts/nuke/api/pipeline.py | 21 ++---- 2 files changed, 52 insertions(+), 69 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 764e904295..90c19707d9 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1,14 +1,13 @@ import os from pprint import pformat import re +import json import six import platform import tempfile import contextlib from collections import OrderedDict -import clique - import nuke from Qt import QtCore, QtWidgets @@ -64,6 +63,7 @@ EXCLUDED_KNOB_TYPE_ON_READ = ( 26, # Text Knob (But for backward compatibility, still be read # if value is not an empty string.) ) +JSON_PREFIX = "JSON:::" class Context: @@ -95,8 +95,38 @@ def get_main_window(): return Context.main_window +def write_create_data(node, knobname, data): + knob_value = JSON_PREFIX + json.dumps(data) + if knobname in node.knobs(): + knob = node[knobname] + knob.setValue(knob_value) + return + + knob = nuke.String_Knob(knobname) + knob.setValue(knob_value) + knob.setFlag(nuke.INVISIBLE) + node.addKnob(knob) + + +def read_create_data(node, knobname): + if knobname not in node.knobs(): + log.debug("get knob: {}".format(node[knobname])) + return + + rawdata = node[knobname].getValue() + if ( + isinstance(rawdata, six.string_types) + and rawdata.startswith(JSON_PREFIX) + ): + try: + return json.loads(rawdata[len(JSON_PREFIX):]) + except json.JSONDecodeError: + return + + class Knobby(object): - """For creating knob which it's type isn't mapped in `create_knobs` + """[DEPRICATED] For creating knob which it's type isn't + mapped in `create_knobs` Args: type (string): Nuke knob type name @@ -121,9 +151,15 @@ class Knobby(object): knob.setFlag(flag) return knob + @staticmethod + def nice_naming(key): + """Convert camelCase name into UI Display Name""" + words = re.findall('[A-Z][^A-Z]*', key[0].upper() + key[1:]) + return " ".join(words) + def create_knobs(data, tab=None): - """Create knobs by data + """[DEPRICATED] Create knobs by data Depending on the type of each dict value and creates the correct Knob. @@ -217,7 +253,7 @@ def create_knobs(data, tab=None): def imprint(node, data, tab=None): - """Store attributes with value on node + """[DEPRICATED] Store attributes with value on node Parse user data into Node knobs. Use `collections.OrderedDict` to ensure knob order. @@ -273,7 +309,7 @@ def imprint(node, data, tab=None): def add_publish_knob(node): - """Add Publish knob to node + """[DEPRICATED] Add Publish knob to node Arguments: node (nuke.Node): nuke node to be processed @@ -291,7 +327,7 @@ def add_publish_knob(node): def set_avalon_knob_data(node, data=None, prefix="avalon:"): - """ Sets data into nodes's avalon knob + """[DEPRICATED] Sets data into nodes's avalon knob Arguments: node (nuke.Node): Nuke node to imprint with data, @@ -353,7 +389,7 @@ def set_avalon_knob_data(node, data=None, prefix="avalon:"): def get_avalon_knob_data(node, prefix="avalon:"): - """ Gets a data from nodes's avalon knob + """[DEPRICATED] Gets a data from nodes's avalon knob Arguments: node (obj): Nuke node to search for data, @@ -393,7 +429,7 @@ def get_avalon_knob_data(node, prefix="avalon:"): def fix_data_for_node_create(data): - """Fixing data to be used for nuke knobs + """[DEPRICATED] Fixing data to be used for nuke knobs """ for k, v in data.items(): if isinstance(v, six.text_type): @@ -404,7 +440,7 @@ def fix_data_for_node_create(data): def add_write_node_legacy(name, **kwarg): - """Adding nuke write node + """[DEPRICATED] Adding nuke write node Arguments: name (str): nuke node name kwarg (attrs): data for nuke knobs @@ -567,7 +603,7 @@ def get_nuke_imageio_settings(): def get_created_node_imageio_setting_legacy(nodeclass, creator, subset): - ''' Get preset data for dataflow (fileType, compression, bitDepth) + '''[DEPRICATED] Get preset data for dataflow (fileType, compression, bitDepth) ''' assert any([creator, nodeclass]), nuke.message( @@ -2811,48 +2847,6 @@ def dirmap_file_name_filter(file_name): return file_name -# ------------------------------------ -# This function seems to be deprecated -# ------------------------------------ -def ls_img_sequence(path): - """Listing all available coherent image sequence from path - - Arguments: - path (str): A nuke's node object - - Returns: - data (dict): with nuke formated path and frameranges - """ - file = os.path.basename(path) - dirpath = os.path.dirname(path) - base, ext = os.path.splitext(file) - name, padding = os.path.splitext(base) - - # populate list of files - files = [ - f for f in os.listdir(dirpath) - if name in f - if ext in f - ] - - # create collection from list of files - collections, reminder = clique.assemble(files) - - if len(collections) > 0: - head = collections[0].format("{head}") - padding = collections[0].format("{padding}") % 1 - padding = "#" * len(padding) - tail = collections[0].format("{tail}") - file = head + padding + tail - - return { - "path": os.path.join(dirpath, file).replace("\\", "/"), - "frames": collections[0].format("[{ranges}]") - } - - return False - - def get_group_io_nodes(nodes): """Get the input and the output of a group of nodes.""" diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 373fd7134b..392573e1f6 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -1,7 +1,6 @@ import nuke import os -import json import importlib from collections import OrderedDict @@ -35,8 +34,6 @@ from openpype.tools.utils import host_tools from .command import viewer_update_and_undo_stop from .lib import ( Context, - imprint, - Knobby, get_main_window, add_publish_knob, WorkfileSettings, @@ -49,7 +46,9 @@ from .lib import ( on_script_load, dirmap_file_name_filter, add_scripts_menu, - add_scripts_gizmo + add_scripts_gizmo, + read_create_data, + write_create_data ) from .lib_template_builder import ( create_placeholder, update_placeholder @@ -137,21 +136,11 @@ class NukeHost( def get_context_data(self): root_node = nuke.root() - context_value = root_node["publish_context"].getValue() - return json.loads(context_value) + return read_create_data(root_node, "publish_context") def update_context_data(self, data, changes): root_node = nuke.root() - imprint( - root_node, - { - "publish_context": Knobby( - "String_Knob", - json.dumps(data), - flags=[nuke.INVISIBLE] - ) - } - ) + write_create_data(root_node, "publish_context", data) def add_nuke_callbacks(): From 69c964d806c993ab4d5b5e72591bdb137bfbb098 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 15 Sep 2022 10:23:24 +0200 Subject: [PATCH 008/211] nuke: new creator wip --- openpype/hosts/nuke/api/lib.py | 55 +++++++++---- openpype/hosts/nuke/api/pipeline.py | 20 +++-- openpype/hosts/nuke/api/plugin.py | 121 +++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 25 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 90c19707d9..9959ed79ea 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -64,6 +64,8 @@ EXCLUDED_KNOB_TYPE_ON_READ = ( # if value is not an empty string.) ) JSON_PREFIX = "JSON:::" +ROOT_DATA_KNOB = "publish_context" +INSTANCE_DATA_KNOB = "publish_instance" class Context: @@ -95,22 +97,32 @@ def get_main_window(): return Context.main_window -def write_create_data(node, knobname, data): - knob_value = JSON_PREFIX + json.dumps(data) +def write_node_data(node, knobname, data): + # if exists then update data if knobname in node.knobs(): - knob = node[knobname] - knob.setValue(knob_value) + log.debug("Updating knobname `{}` on node `{}`".format( + knobname, node.name() + )) + update_node_data(node, knobname, data) return + log.debug("Creating knobname `{}` on node `{}`".format( + knobname, node.name() + )) + # else create new + knob_value = JSON_PREFIX + json.dumps(data) knob = nuke.String_Knob(knobname) knob.setValue(knob_value) knob.setFlag(nuke.INVISIBLE) node.addKnob(knob) -def read_create_data(node, knobname): +def read_node_data(node, knobname): + if knobname not in node.knobs(): - log.debug("get knob: {}".format(node[knobname])) + log.warnig("Knobname `{}` does not exist on node `{}`".format( + knobname, node.name() + )) return rawdata = node[knobname].getValue() @@ -124,6 +136,14 @@ def read_create_data(node, knobname): return +def update_node_data(node, knobname, data): + knob = node[knobname] + node_data = read_node_data(node, knobname) + node_data.update(data) + knob_value = JSON_PREFIX + json.dumps(node_data) + knob.setValue(knob_value) + + class Knobby(object): """[DEPRICATED] For creating knob which it's type isn't mapped in `create_knobs` @@ -2168,11 +2188,14 @@ class WorkfileSettings(object): node['frame_range_lock'].setValue(True) # adding handle_start/end to root avalon knob - if not set_avalon_knob_data(self._root_node, { - "handleStart": int(handle_start), - "handleEnd": int(handle_end) - }): - log.warning("Cannot set Avalon knob to Root node!") + write_node_data( + self._root_node, + INSTANCE_DATA_KNOB, + { + "handleStart": int(handle_start), + "handleEnd": int(handle_end) + } + ) def reset_resolution(self): """Set resolution to project resolution.""" @@ -2295,7 +2318,6 @@ def get_write_node_template_attr(node): subset=avalon_knob_data["subset"] ) - # collecting correct data correct_data = OrderedDict() @@ -2347,10 +2369,11 @@ def get_dependent_nodes(nodes): def find_free_space_to_paste_nodes( - nodes, - group=nuke.root(), - direction="right", - offset=300): + nodes, + group=nuke.root(), + direction="right", + offset=300 +): """ For getting coordinates in DAG (node graph) for placing new nodes diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 392573e1f6..a18d3b54e7 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -34,6 +34,7 @@ from openpype.tools.utils import host_tools from .command import viewer_update_and_undo_stop from .lib import ( Context, + ROOT_DATA_KNOB, get_main_window, add_publish_knob, WorkfileSettings, @@ -47,8 +48,8 @@ from .lib import ( dirmap_file_name_filter, add_scripts_menu, add_scripts_gizmo, - read_create_data, - write_create_data + read_node_data, + write_node_data ) from .lib_template_builder import ( create_placeholder, update_placeholder @@ -136,11 +137,11 @@ class NukeHost( def get_context_data(self): root_node = nuke.root() - return read_create_data(root_node, "publish_context") + return read_node_data(root_node, ROOT_DATA_KNOB) def update_context_data(self, data, changes): root_node = nuke.root() - write_create_data(root_node, "publish_context", data) + write_node_data(root_node, ROOT_DATA_KNOB, data) def add_nuke_callbacks(): @@ -492,7 +493,7 @@ def ls(): yield container -def list_instances(): +def list_instances(creator_id=None): """List all created instances to publish from current workfile. For SubsetManager @@ -514,7 +515,7 @@ def list_instances(): # get data from avalon knob avalon_knob_data = get_avalon_knob_data( - node, ["avalon:", "ak:"]) + node) if not avalon_knob_data: continue @@ -522,8 +523,13 @@ def list_instances(): if avalon_knob_data["id"] != "pyblish.avalon.instance": continue + if creator_id and avalon_knob_data["identifier"] != creator_id: + continue + # add node name - avalon_knob_data["name"] = node.name() + avalon_knob_data.update({ + "instance_node": node + }) instances.append(avalon_knob_data) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 37ce03dc55..302d6c5cd7 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,15 +1,23 @@ +import nuke + import os +import sys +import six import random import string from collections import OrderedDict from abc import abstractmethod - -import nuke +from abc import ( + ABCMeta +) from openpype.api import get_current_project_settings from openpype.pipeline import ( LegacyCreator, LoaderPlugin, + CreatorError, + Creator as NewCreator, + CreatedInstance ) from .lib import ( Knobby, @@ -21,6 +29,115 @@ from .lib import ( set_node_knobs_from_settings, get_view_process_node ) +from .pipeline import ( + list_instances +) + + +class OpenPypeCreatorError(CreatorError): + pass + + +@six.add_metaclass(ABCMeta) +class NukeCreator(NewCreator): + selected_nodes = [] + + def _create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type="NoOp" + ): + """Create node representing instance. + + Arguments: + node_name (str): Name of the new node. + knobs (OrderedDict): knobs name and values + parent (str): Name of the parent node. + node_type (str, optional): Type of the node. + + Returns: + nuke.Node: Newly created instance node. + + """ + node_knobs = knobs or {} + + # set parent node + parent_node = nuke.root() + if parent: + parent_node = nuke.toNode(parent) + + with parent_node: + created_node = nuke.createNode(node_type) + created_node["name"].setValue(node_name) + + for key, values in node_knobs.items(): + if key in created_node.knobs(): + created_node["key"].setValue(values) + + return created_node + + # def create(self, subset_name, instance_data, pre_create_data): + # try: + # if pre_create_data.get("use_selection"): + # self.selected_nodes = nuke.selectedNodes() + + # # Get the node type and remove it from the data, not needed + # _node_type = instance_data.pop("node_type", None) + # if _node_type is None: + # _node_type = "NoOp" + + # instance_node = self._create_instance_node( + # subset_name, node_type=_node_type, pre_create_data) + + # instance_data["instance_node"] = instance_node.path() + + # instance = CreatedInstance( + # self.family, + # subset_name, + # instance_data, + # self) + # self._add_instance_to_context(instance) + # imprint(instance_node, instance.data_to_store()) + # return instance + + # except hou.Error as er: + # six.reraise( + # OpenPypeCreatorError, + # OpenPypeCreatorError("Creator error: {}".format(er)), + # sys.exc_info()[2]) + + # def collect_instances(self): + # for instance_data in list_instances(creator_id=self.identifier): + # created_instance = CreatedInstance.from_existing( + # instance_data, self + # ) + # self._add_instance_to_context(created_instance) + + # def update_instances(self, update_list): + # for created_inst, _changes in update_list: + # instance_node = created_inst.pop("instance_node", None) + # current_data = created_inst.data + + # imprint( + # instance_node, + # { + # key: value[1] for key, value in _changes.items() + # if current_data.get(key) != value[1] + # }, + # update=True + # ) + + # def remove_instances(self, instances): + # for instance in instances: + # remove_instance(instance) + # self._remove_instance_from_context(instance) + + # def get_pre_create_attr_defs(self): + # return [ + # BoolDef("use_selection", label="Use selection") + # ] class OpenPypeCreator(LegacyCreator): From 13f9789dd2308921449536d9a1aa77e2afeb5184 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 13:00:39 +0200 Subject: [PATCH 009/211] nuke: renaming and fixing node data setter and getter --- openpype/hosts/nuke/api/lib.py | 22 ++++++++++++++-------- openpype/hosts/nuke/api/pipeline.py | 9 +++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 9959ed79ea..d61d8c161e 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -97,7 +97,8 @@ def get_main_window(): return Context.main_window -def write_node_data(node, knobname, data): +def set_node_data(node, knobname, data): + # TODO: doc string # if exists then update data if knobname in node.knobs(): log.debug("Updating knobname `{}` on node `{}`".format( @@ -107,8 +108,8 @@ def write_node_data(node, knobname, data): return log.debug("Creating knobname `{}` on node `{}`".format( - knobname, node.name() - )) + knobname, node.name() + )) # else create new knob_value = JSON_PREFIX + json.dumps(data) knob = nuke.String_Knob(knobname) @@ -117,8 +118,8 @@ def write_node_data(node, knobname, data): node.addKnob(knob) -def read_node_data(node, knobname): - +def get_node_data(node, knobname): + # TODO: doc string if knobname not in node.knobs(): log.warnig("Knobname `{}` does not exist on node `{}`".format( knobname, node.name() @@ -137,8 +138,9 @@ def read_node_data(node, knobname): def update_node_data(node, knobname, data): + # TODO: doc string knob = node[knobname] - node_data = read_node_data(node, knobname) + node_data = get_node_data(node, knobname) or {} node_data.update(data) knob_value = JSON_PREFIX + json.dumps(node_data) knob.setValue(knob_value) @@ -2179,7 +2181,8 @@ class WorkfileSettings(object): range = '{0}-{1}'.format( int(data["frameStart"]), - int(data["frameEnd"])) + int(data["frameEnd"]) + ) for node in nuke.allNodes(filter="Viewer"): node['frame_range'].setValue(range) @@ -2188,7 +2191,10 @@ class WorkfileSettings(object): node['frame_range_lock'].setValue(True) # adding handle_start/end to root avalon knob - write_node_data( + log.debug("self._root_node: {}".format(self._root_node)) + log.debug("self._root_node: {}".format(self._root_node)) + + set_node_data( self._root_node, INSTANCE_DATA_KNOB, { diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index ddc93d7256..3a8c235ee4 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -44,8 +44,9 @@ from .lib import ( dirmap_file_name_filter, add_scripts_menu, add_scripts_gizmo, - read_node_data, - write_node_data + get_node_data, + set_node_data, + update_node_data ) from .workfile_template_builder import ( NukePlaceholderLoadPlugin, @@ -137,11 +138,11 @@ class NukeHost( def get_context_data(self): root_node = nuke.root() - return read_node_data(root_node, ROOT_DATA_KNOB) + return get_node_data(root_node, ROOT_DATA_KNOB) def update_context_data(self, data, changes): root_node = nuke.root() - write_node_data(root_node, ROOT_DATA_KNOB, data) + set_node_data(root_node, ROOT_DATA_KNOB, data) def add_nuke_callbacks(): From 615b7780918f8659c6e559817bacaa7b549e661b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 13:07:02 +0200 Subject: [PATCH 010/211] Nuke: adding docstrings --- openpype/hosts/nuke/api/lib.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index d61d8c161e..d9d3752d10 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -98,7 +98,16 @@ def get_main_window(): def set_node_data(node, knobname, data): - # TODO: doc string + """Write data to node invisible knob + + Will create new in case it doesnt exists + or update the one already created. + + Args: + node (nuke.Node): node object + knobname (str): knob name + data (dict): data to be stored in knob + """ # if exists then update data if knobname in node.knobs(): log.debug("Updating knobname `{}` on node `{}`".format( @@ -119,7 +128,15 @@ def set_node_data(node, knobname, data): def get_node_data(node, knobname): - # TODO: doc string + """Read data from node. + + Args: + node (nuke.Node): node object + knobname (str): knob name + + Returns: + dict: data stored in knob + """ if knobname not in node.knobs(): log.warnig("Knobname `{}` does not exist on node `{}`".format( knobname, node.name() @@ -138,7 +155,13 @@ def get_node_data(node, knobname): def update_node_data(node, knobname, data): - # TODO: doc string + """Update already present data. + + Args: + node (nuke.Node): node object + knobname (str): knob name + data (dict): data to update knob value + """ knob = node[knobname] node_data = get_node_data(node, knobname) or {} node_data.update(data) From 6a657f9d1a8a9df5ed485261633275a5939599ba Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:32:39 +0200 Subject: [PATCH 011/211] nuke: updating api --- openpype/hosts/nuke/api/__init__.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 0cbae94bc5..002e4e3dc6 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -9,7 +9,11 @@ from .workio import ( from .command import ( viewer_update_and_undo_stop ) -from .plugin import OpenPypeCreator +from .plugin import ( + NukeCreator, + NukeCreatorError, + OpenPypeCreator +) from .pipeline import ( NukeHost, @@ -26,11 +30,16 @@ from .pipeline import ( get_workfile_build_placeholder_plugins, ) from .lib import ( + INSTANCE_DATA_KNOB, + ROOT_DATA_KNOB, maintained_selection, reset_selection, get_view_process_node, duplicate_node, - convert_knob_value_to_correct_type + convert_knob_value_to_correct_type, + get_node_data, + set_node_data, + update_node_data ) from .utils import ( colorspace_exists_on_node, @@ -47,6 +56,8 @@ __all__ = ( "viewer_update_and_undo_stop", + "NukeCreator", + "NukeCreatorError", "OpenPypeCreator", "NukeHost", @@ -62,11 +73,16 @@ __all__ = ( "get_workfile_build_placeholder_plugins", + "INSTANCE_DATA_KNOB", + "ROOT_DATA_KNOB", "maintained_selection", "reset_selection", "get_view_process_node", "duplicate_node", "convert_knob_value_to_correct_type", + "get_node_data", + "set_node_data", + "update_node_data", "colorspace_exists_on_node", "get_colorspace_list" From 4a890a452d162110b93bca99a38129f12443d1e6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:36:54 +0200 Subject: [PATCH 012/211] nuke: removing create from menu --- openpype/hosts/nuke/api/pipeline.py | 10 +++------- openpype/settings/defaults/project_settings/nuke.json | 1 - .../schemas/projects_schema/schema_project_nuke.json | 5 ----- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 3a8c235ee4..5abe182c5e 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -231,8 +231,8 @@ def _install_menu(): menu.addSeparator() menu.addCommand( - "Create...", - lambda: host_tools.show_creator(parent=main_window) + "Publish...", + lambda: host_tools.show_publisher(parent=main_window) ) menu.addCommand( "Load...", @@ -241,14 +241,11 @@ def _install_menu(): use_context=True ) ) - menu.addCommand( - "Publish...", - lambda: host_tools.show_publisher(parent=main_window) - ) menu.addCommand( "Manage...", lambda: host_tools.show_scene_inventory(parent=main_window) ) + menu.addSeparator() menu.addCommand( "Library...", lambda: host_tools.show_library_loader( @@ -344,7 +341,6 @@ def add_shortcuts_from_presets(): if nuke_presets.get("menu"): menu_label_mapping = { "manage": "Manage...", - "create": "Create...", "load": "Load...", "build_workfile": "Build Workfile", "publish": "Publish..." diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index c3eda2cbb4..7b3d07d441 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -1,7 +1,6 @@ { "general": { "menu": { - "create": "ctrl+shift+alt+c", "publish": "ctrl+alt+p", "load": "ctrl+alt+l", "manage": "ctrl+alt+m", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index 7cf82b9e69..c21df7d44d 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -17,11 +17,6 @@ "key": "menu", "label": "OpenPype Menu shortcuts", "children": [ - { - "type": "text", - "key": "create", - "label": "Create..." - }, { "type": "text", "key": "publish", From 1ce3fa421a61722815653f34f585f9589b20c9e8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:37:59 +0200 Subject: [PATCH 013/211] nuke: adding abstract NukeCreator class --- openpype/hosts/nuke/api/plugin.py | 133 ++++++++++++++++-------------- 1 file changed, 73 insertions(+), 60 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 302d6c5cd7..5ac144b2c7 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -12,6 +12,7 @@ from abc import ( ) from openpype.api import get_current_project_settings +from openpype.lib import BoolDef from openpype.pipeline import ( LegacyCreator, LoaderPlugin, @@ -20,6 +21,7 @@ from openpype.pipeline import ( CreatedInstance ) from .lib import ( + INSTANCE_DATA_KNOB, Knobby, check_subsetname_exists, maintained_selection, @@ -27,14 +29,16 @@ from .lib import ( add_publish_knob, get_nuke_imageio_settings, set_node_knobs_from_settings, - get_view_process_node + get_view_process_node, + set_node_data ) from .pipeline import ( - list_instances + list_instances, + remove_instance ) -class OpenPypeCreatorError(CreatorError): +class NukeCreatorError(CreatorError): pass @@ -47,7 +51,7 @@ class NukeCreator(NewCreator): node_name, knobs=None, parent=None, - node_type="NoOp" + node_type=None ): """Create node representing instance. @@ -61,6 +65,8 @@ class NukeCreator(NewCreator): nuke.Node: Newly created instance node. """ + node_type = node_type or "NoOp" + node_knobs = knobs or {} # set parent node @@ -68,76 +74,83 @@ class NukeCreator(NewCreator): if parent: parent_node = nuke.toNode(parent) - with parent_node: - created_node = nuke.createNode(node_type) - created_node["name"].setValue(node_name) + try: + with parent_node: + created_node = nuke.createNode(node_type) + created_node["name"].setValue(node_name) - for key, values in node_knobs.items(): - if key in created_node.knobs(): - created_node["key"].setValue(values) + for key, values in node_knobs.items(): + if key in created_node.knobs(): + created_node["key"].setValue(values) + except Exception as _err: + raise NukeCreatorError("Creating have failed: {}".format(_err)) return created_node - # def create(self, subset_name, instance_data, pre_create_data): - # try: - # if pre_create_data.get("use_selection"): - # self.selected_nodes = nuke.selectedNodes() + def create(self, subset_name, instance_data, pre_create_data): + try: + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + else: + self.selected_nodes = None - # # Get the node type and remove it from the data, not needed - # _node_type = instance_data.pop("node_type", None) - # if _node_type is None: - # _node_type = "NoOp" + instance_node = self._create_instance_node( + subset_name, + node_type=instance_data.pop("node_type", None) + ) - # instance_node = self._create_instance_node( - # subset_name, node_type=_node_type, pre_create_data) + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self) - # instance_data["instance_node"] = instance_node.path() + instance.transient_data["node"] = instance_node - # instance = CreatedInstance( - # self.family, - # subset_name, - # instance_data, - # self) - # self._add_instance_to_context(instance) - # imprint(instance_node, instance.data_to_store()) - # return instance + self._add_instance_to_context(instance) - # except hou.Error as er: - # six.reraise( - # OpenPypeCreatorError, - # OpenPypeCreatorError("Creator error: {}".format(er)), - # sys.exc_info()[2]) + set_node_data( + instance_node, INSTANCE_DATA_KNOB, instance.data_to_store()) - # def collect_instances(self): - # for instance_data in list_instances(creator_id=self.identifier): - # created_instance = CreatedInstance.from_existing( - # instance_data, self - # ) - # self._add_instance_to_context(created_instance) + return instance - # def update_instances(self, update_list): - # for created_inst, _changes in update_list: - # instance_node = created_inst.pop("instance_node", None) - # current_data = created_inst.data + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2]) - # imprint( - # instance_node, - # { - # key: value[1] for key, value in _changes.items() - # if current_data.get(key) != value[1] - # }, - # update=True - # ) + def collect_instances(self): + for (node, data) in list_instances(creator_id=self.identifier): + created_instance = CreatedInstance.from_existing( + data, self + ) + created_instance.transient_data["node"] = node + self._add_instance_to_context(created_instance) - # def remove_instances(self, instances): - # for instance in instances: - # remove_instance(instance) - # self._remove_instance_from_context(instance) + def update_instances(self, update_list): + for created_inst, _changes in update_list: + instance_node = created_inst.transient_data["node"] + current_data = created_inst.data - # def get_pre_create_attr_defs(self): - # return [ - # BoolDef("use_selection", label="Use selection") - # ] + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + { + key: value[1] for key, value in _changes.items() + if current_data.get(key) != value[1] + } + ) + + def remove_instances(self, instances): + for instance in instances: + remove_instance(instance) + self._remove_instance_from_context(instance) + + def get_pre_create_attr_defs(self): + return [ + BoolDef("use_selection", label="Use selection") + ] class OpenPypeCreator(LegacyCreator): From 02ac5c19e93970e5c86411eaa5b6c28db72cd6ff Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:39:01 +0200 Subject: [PATCH 014/211] nuke: improving workfile creator --- .../nuke/plugins/create/workfile_creator.py | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index 9ceaf376c1..f2227737b4 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -5,6 +5,7 @@ from openpype.pipeline import ( CreatedInstance, legacy_io, ) +import nuke class WorkfileCreator(AutoCreator): @@ -17,14 +18,37 @@ class WorkfileCreator(AutoCreator): return [] def collect_instances(self): - for instance_data in api.list_instances(): - creator_id = instance_data.get("creator_identifier") - if creator_id == self.identifier: - subset_name = instance_data["subset"] - instance = CreatedInstance( - self.family, subset_name, instance_data, self - ) - self._add_instance_to_context(instance) + root_node = nuke.root() + instance_data = api.get_node_data( + root_node, api.INSTANCE_DATA_KNOB + ) + self.log.debug("__ instance_data: {}".format(instance_data)) + + project_name = legacy_io.Session["AVALON_PROJECT"] + asset_name = legacy_io.Session["AVALON_ASSET"] + task_name = legacy_io.Session["AVALON_TASK"] + host_name = legacy_io.Session["AVALON_APP"] + + asset_doc = get_asset_by_name(project_name, asset_name) + subset_name = self.get_subset_name( + self.default_variant, task_name, asset_doc, + project_name, host_name + ) + self.log.debug("__ subset_name: {}".format(subset_name)) + instance_data.update({ + "asset": asset_name, + "task": task_name, + "variant": self.default_variant + }) + instance_data.update(self.get_dynamic_data( + self.default_variant, task_name, asset_doc, + project_name, host_name + )) + + instance = CreatedInstance( + self.family, subset_name, instance_data, self + ) + self._add_instance_to_context(instance) def update_instances(self, update_list): # nothing to change on workfiles @@ -42,6 +66,8 @@ class WorkfileCreator(AutoCreator): task_name = legacy_io.Session["AVALON_TASK"] host_name = legacy_io.Session["AVALON_APP"] + self.log.debug("__ existing_instance: {}".format(existing_instance)) + if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( From 7b30692171bd377e6718f59e0d65dae2e8bb98f1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:44:21 +0200 Subject: [PATCH 015/211] nuke: improving list/remove/select instance functions --- openpype/hosts/nuke/api/pipeline.py | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 5abe182c5e..ecf38812cc 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -31,6 +31,7 @@ from .command import viewer_update_and_undo_stop from .lib import ( Context, ROOT_DATA_KNOB, + INSTANCE_DATA_KNOB, get_main_window, add_publish_knob, WorkfileSettings, @@ -504,8 +505,8 @@ def list_instances(creator_id=None): Returns: (list) of dictionaries matching instances format """ - instances = [] - for node in nuke.allNodes(): + listed_instances = [] + for node in nuke.allNodes(recurseGroups=True): if node.Class() in ["Viewer", "Dot"]: continue @@ -513,30 +514,29 @@ def list_instances(creator_id=None): try: if node["disable"].value(): continue - except Exception as E: - log.warning(E) + except Exception as _exc: + log.debug("Node {} have no disable knob - {}".format( + node.fullName(), _exc)) # get data from avalon knob - avalon_knob_data = get_avalon_knob_data( - node) + instance_data = get_node_data( + node, INSTANCE_DATA_KNOB) - if not avalon_knob_data: + if not instance_data: continue - if avalon_knob_data["id"] != "pyblish.avalon.instance": + if instance_data["id"] != "pyblish.avalon.instance": continue - if creator_id and avalon_knob_data["identifier"] != creator_id: + log.debug("_ creator_id: {}".format(creator_id)) + if creator_id and instance_data["creator_identifier"] != creator_id: continue - # add node name - avalon_knob_data.update({ - "instance_node": node - }) + listed_instances.append((node, instance_data)) instances.append(avalon_knob_data) - return instances + return listed_instances def remove_instance(instance): @@ -547,8 +547,8 @@ def remove_instance(instance): Args: instance (dict): instance representation from subsetmanager model """ - node = nuke.toNode(instance["name"]) - nuke.delete(node) + instance_node = instance.transient_data["node"] + nuke.delete(instance_node) def select_instance(instance): @@ -558,5 +558,5 @@ def select_instance(instance): Args: instance (dict): instance representation from subsetmanager model """ - node = nuke.toNode(instance["name"]) - node["selected"].setValue(True) + instance_node = instance.transient_data["node"] + instance_node["selected"].setValue(True) From e84eb355b6c978cb978487a74fc11c4f83bc1caf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:46:25 +0200 Subject: [PATCH 016/211] nuke: remove residual code --- openpype/hosts/nuke/api/pipeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index ecf38812cc..cbe8b547c6 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -534,8 +534,6 @@ def list_instances(creator_id=None): listed_instances.append((node, instance_data)) - instances.append(avalon_knob_data) - return listed_instances From 9e609984e1b2b9225f49e7b2e3b60ac0be13dcfb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:46:53 +0200 Subject: [PATCH 017/211] nuke: no need to log --- openpype/hosts/nuke/api/lib.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index d9d3752d10..211bab2d80 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -138,9 +138,6 @@ def get_node_data(node, knobname): dict: data stored in knob """ if knobname not in node.knobs(): - log.warnig("Knobname `{}` does not exist on node `{}`".format( - knobname, node.name() - )) return rawdata = node[knobname].getValue() @@ -2213,10 +2210,6 @@ class WorkfileSettings(object): node['frame_range'].setValue(range) node['frame_range_lock'].setValue(True) - # adding handle_start/end to root avalon knob - log.debug("self._root_node: {}".format(self._root_node)) - log.debug("self._root_node: {}".format(self._root_node)) - set_node_data( self._root_node, INSTANCE_DATA_KNOB, From 541b9d41f2460e4da3a24f4188ec3309546a992a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 22:25:02 +0200 Subject: [PATCH 018/211] nuke: workfile creator cleaning --- .../nuke/plugins/create/workfile_creator.py | 50 ++----------------- 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index f2227737b4..ae54d6bcb2 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -48,6 +48,7 @@ class WorkfileCreator(AutoCreator): instance = CreatedInstance( self.family, subset_name, instance_data, self ) + instance.transient_data["node"] = root_node self._add_instance_to_context(instance) def update_instances(self, update_list): @@ -55,49 +56,6 @@ class WorkfileCreator(AutoCreator): pass def create(self, options=None): - existing_instance = None - for instance in self.create_context.instances: - if instance.family == self.family: - existing_instance = instance - break - - project_name = legacy_io.Session["AVALON_PROJECT"] - asset_name = legacy_io.Session["AVALON_ASSET"] - task_name = legacy_io.Session["AVALON_TASK"] - host_name = legacy_io.Session["AVALON_APP"] - - self.log.debug("__ existing_instance: {}".format(existing_instance)) - - if existing_instance is None: - asset_doc = get_asset_by_name(project_name, asset_name) - subset_name = self.get_subset_name( - self.default_variant, task_name, asset_doc, - project_name, host_name - ) - data = { - "asset": asset_name, - "task": task_name, - "variant": self.default_variant - } - data.update(self.get_dynamic_data( - self.default_variant, task_name, asset_doc, - project_name, host_name - )) - - new_instance = CreatedInstance( - self.family, subset_name, data, self - ) - self._add_instance_to_context(new_instance) - - elif ( - existing_instance["asset"] != asset_name - or existing_instance["task"] != task_name - ): - asset_doc = get_asset_by_name(project_name, asset_name) - subset_name = self.get_subset_name( - self.default_variant, task_name, asset_doc, - project_name, host_name - ) - existing_instance["asset"] = asset_name - existing_instance["task"] = task_name - existing_instance["subset"] = subset_name + # no need to create if it is created + # in `collect_instances` + pass From 5cde873d504e71970868301d33ffe4ffae4daaa5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 22:25:10 +0200 Subject: [PATCH 019/211] fixing updating --- openpype/hosts/nuke/api/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 5ac144b2c7..af29fa2dd1 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -138,7 +138,7 @@ class NukeCreator(NewCreator): INSTANCE_DATA_KNOB, { key: value[1] for key, value in _changes.items() - if current_data.get(key) != value[1] + if current_data.get(key) != value[0] } ) From 495ea784148687c3e9a6437b9a949d0dfd17f71b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 12:31:54 +0200 Subject: [PATCH 020/211] nuke: refactory Backdrop Creator to new publisher --- openpype/hosts/nuke/api/__init__.py | 2 + openpype/hosts/nuke/api/plugin.py | 81 ++++++++++++++---- .../nuke/plugins/create/create_backdrop.py | 85 +++++++++---------- 3 files changed, 109 insertions(+), 59 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 002e4e3dc6..8b18d4bc3b 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -34,6 +34,7 @@ from .lib import ( ROOT_DATA_KNOB, maintained_selection, reset_selection, + select_nodes, get_view_process_node, duplicate_node, convert_knob_value_to_correct_type, @@ -77,6 +78,7 @@ __all__ = ( "ROOT_DATA_KNOB", "maintained_selection", "reset_selection", + "select_nodes", "get_view_process_node", "duplicate_node", "convert_knob_value_to_correct_type", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index af29fa2dd1..7cb8bc8b84 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -7,8 +7,10 @@ import random import string from collections import OrderedDict from abc import abstractmethod -from abc import ( - ABCMeta + +from openpype.client import ( + get_asset_by_name, + get_subsets, ) from openpype.api import get_current_project_settings @@ -18,7 +20,8 @@ from openpype.pipeline import ( LoaderPlugin, CreatorError, Creator as NewCreator, - CreatedInstance + CreatedInstance, + legacy_io ) from .lib import ( INSTANCE_DATA_KNOB, @@ -42,11 +45,39 @@ class NukeCreatorError(CreatorError): pass -@six.add_metaclass(ABCMeta) class NukeCreator(NewCreator): selected_nodes = [] - def _create_instance_node( + def add_info_knob(self, node): + if "OP_info" in node.knobs().keys(): + return + + # add info text + info_knob = nuke.Text_Knob("OP_info", "") + info_knob.setValue(""" +

Do not erase manually !

+

This node is maintained by OpenPype Publisher.

+

We recomand to remove it from the Publisher gui.

+ """) + node.addKnob(info_knob) + + def check_existing_subset(self, subset_name, instance_data): + """Check if existing subset name versions already exists.""" + # Get all subsets of the current asset + project_name = legacy_io.active_project() + asset_doc = get_asset_by_name( + project_name, instance_data["asset"], fields=["_id"] + ) + subset_docs = get_subsets( + project_name, asset_ids=[asset_doc["_id"]], fields=["name"] + ) + existing_subset_names_low = { + subset_doc["name"].lower() + for subset_doc in subset_docs + } + return subset_name.lower() in existing_subset_names_low + + def create_instance_node( self, node_name, knobs=None, @@ -57,9 +88,9 @@ class NukeCreator(NewCreator): Arguments: node_name (str): Name of the new node. - knobs (OrderedDict): knobs name and values + knobs (OrderedDict): node knobs name and values parent (str): Name of the parent node. - node_type (str, optional): Type of the node. + node_type (str, optional): Nuke node Class. Returns: nuke.Node: Newly created instance node. @@ -79,6 +110,8 @@ class NukeCreator(NewCreator): created_node = nuke.createNode(node_type) created_node["name"].setValue(node_name) + self.add_info_knob(created_node) + for key, values in node_knobs.items(): if key in created_node.knobs(): created_node["key"].setValue(values) @@ -87,23 +120,39 @@ class NukeCreator(NewCreator): return created_node - def create(self, subset_name, instance_data, pre_create_data): - try: - if pre_create_data.get("use_selection"): - self.selected_nodes = nuke.selectedNodes() - else: - self.selected_nodes = None + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + else: + self.selected_nodes = [] - instance_node = self._create_instance_node( + self.log.debug("Selection is: {}".format(self.selected_nodes)) + + def create(self, subset_name, instance_data, pre_create_data): + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published with different HDA" + "definition.").format(subset_name)) + + try: + + instance_node = self.create_instance_node( subset_name, node_type=instance_data.pop("node_type", None) ) - instance = CreatedInstance( self.family, subset_name, instance_data, - self) + self + ) instance.transient_data["node"] = instance_node diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index 0c11b3f274..e622fd12be 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -1,56 +1,55 @@ -import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - select_nodes, - set_avalon_knob_data +from nukescripts import autoBackdrop + +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection, + select_nodes + ) -class CreateBackdrop(plugin.OpenPypeCreator): +class CreateBackdrop(NukeCreator): """Add Publishable Backdrop""" - name = "nukenodes" + identifier = "create_backdrop" label = "Create Backdrop" family = "nukenodes" icon = "file-archive-o" - defaults = ["Main"] + maintain_selection = True - def __init__(self, *args, **kwargs): - super(CreateBackdrop, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xdfea5dff" - return + # plugin attributes + node_color = "0xdfea5dff" - def process(self): - from nukescripts import autoBackdrop - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if len(self.selected_nodes) >= 1: + select_nodes(self.selected_nodes) - if len(nodes) >= 1: - select_nodes(nodes) - bckd_node = autoBackdrop() - bckd_node["name"].setValue("{}_BDN".format(self.name)) - bckd_node["tile_color"].setValue(int(self.node_color, 16)) - bckd_node["note_font_size"].setValue(24) - bckd_node["label"].setValue("[{}]".format(self.name)) - # add avalon knobs - instance = set_avalon_knob_data(bckd_node, self.data) + created_node = autoBackdrop() + created_node["name"].setValue(node_name) + created_node["tile_color"].setValue(int(self.node_color, 16)) + created_node["note_font_size"].setValue(24) + created_node["label"].setValue("[{}]".format(node_name)) - return instance - else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return - else: - bckd_node = autoBackdrop() - bckd_node["name"].setValue("{}_BDN".format(self.name)) - bckd_node["tile_color"].setValue(int(self.node_color, 16)) - bckd_node["note_font_size"].setValue(24) - bckd_node["label"].setValue("[{}]".format(self.name)) - # add avalon knobs - instance = set_avalon_knob_data(bckd_node, self.data) + return created_node - return instance + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published with different HDA" + "definition.").format(subset_name)) + + instance = super(CreateBackdrop, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance From 72dd122809fc29dddadabebf9692d60ab6043cab Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 12:58:38 +0200 Subject: [PATCH 021/211] nuke: refactory publishing backdrop to new publisher --- .../nuke/plugins/publish/collect_backdrop.py | 18 +++++++++---- .../nuke/plugins/publish/extract_backdrop.py | 26 +++++++++---------- .../nuke/plugins/publish/validate_backdrop.py | 7 ++--- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 4efbb88b8c..688b1054ab 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -1,3 +1,4 @@ +from pprint import pformat import pyblish.api from openpype.hosts.nuke.api import lib as pnlib import nuke @@ -14,8 +15,14 @@ class CollectBackdrops(pyblish.api.InstancePlugin): families = ["nukenodes"] def process(self, instance): + self.log.debug(pformat(instance.data)) - bckn = instance[0] + # new publisher way + if instance.data.get("transientData"): + bckn = instance.data["transientData"]["node"] + else: + # or backward compatible + bckn = instance[0] # define size of the backdrop left = bckn.xpos() @@ -23,6 +30,7 @@ class CollectBackdrops(pyblish.api.InstancePlugin): right = left + bckn['bdwidth'].value() bottom = top + bckn['bdheight'].value() + instance.data["transientData"]["childNodes"] = [] # iterate all nodes for node in nuke.allNodes(): @@ -37,13 +45,13 @@ class CollectBackdrops(pyblish.api.InstancePlugin): and (node.ypos() + node.screenHeight() < bottom): # add contained nodes to instance's node list - instance.append(node) + instance.data["transientData"]["childNodes"].append(node) # get all connections from outside of backdrop - nodes = instance[1:] + nodes = instance.data["transientData"]["childNodes"] connections_in, connections_out = pnlib.get_dependent_nodes(nodes) - instance.data["nodeConnectionsIn"] = connections_in - instance.data["nodeConnectionsOut"] = connections_out + instance.data["transientData"]["nodeConnectionsIn"] = connections_in + instance.data["transientData"]["nodeConnectionsOut"] = connections_out # make label nicer instance.data["label"] = "{0} ({1} nodes)".format( diff --git a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py index d1e5c4cc5a..e62c715b9c 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py @@ -26,8 +26,14 @@ class ExtractBackdropNode(publish.Extractor): families = ["nukenodes"] def process(self, instance): - tmp_nodes = list() - nodes = instance[1:] + tmp_nodes = [] + child_nodes = instance.data["transientData"]["childNodes"] + # all connections outside of backdrop + connections_in = instance.data["transientData"]["nodeConnectionsIn"] + connections_out = instance.data["transientData"]["nodeConnectionsOut"] + self.log.debug("_ connections_in: `{}`".format(connections_in)) + self.log.debug("_ connections_out: `{}`".format(connections_out)) + # Define extract output file path stagingdir = self.staging_dir(instance) filename = "{0}.nk".format(instance.name) @@ -35,20 +41,14 @@ class ExtractBackdropNode(publish.Extractor): # maintain selection with maintained_selection(): - # all connections outside of backdrop - connections_in = instance.data["nodeConnectionsIn"] - connections_out = instance.data["nodeConnectionsOut"] - self.log.debug("_ connections_in: `{}`".format(connections_in)) - self.log.debug("_ connections_out: `{}`".format(connections_out)) - - # create input nodes and name them as passing node (*_INP) + # create input child_nodes and name them as passing node (*_INP) for n, inputs in connections_in.items(): for i, input in inputs: inpn = nuke.createNode("Input") inpn["name"].setValue("{}_{}_INP".format(n.name(), i)) n.setInput(i, inpn) inpn.setXYpos(input.xpos(), input.ypos()) - nodes.append(inpn) + child_nodes.append(inpn) tmp_nodes.append(inpn) reset_selection() @@ -63,13 +63,13 @@ class ExtractBackdropNode(publish.Extractor): if d.name() in n.name()), 0), opn) opn.setInput(0, n) opn.autoplace() - nodes.append(opn) + child_nodes.append(opn) tmp_nodes.append(opn) reset_selection() - # select nodes to copy + # select child_nodes to copy reset_selection() - select_nodes(nodes) + select_nodes(child_nodes) # create tmp nk file # save file to the path nuke.nodeCopy(path) diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index 17dc79dc56..7ce3ce0e3f 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -60,7 +60,8 @@ class ValidateBackdrop(pyblish.api.InstancePlugin): actions = [SelectCenterInNodeGraph] def process(self, instance): - connections_out = instance.data["nodeConnectionsOut"] + child_nodes = instance.data["transientData"]["childNodes"] + connections_out = instance.data["transientData"]["nodeConnectionsOut"] msg_multiple_outputs = ( "Only one outcoming connection from " @@ -78,10 +79,10 @@ class ValidateBackdrop(pyblish.api.InstancePlugin): self.log.debug( "Amount of nodes on instance: {}".format( - len(instance)) + len(child_nodes)) ) - if len(instance) == 1: + if child_nodes == []: raise PublishXmlValidationError( self, msg_no_nodes, From 4df13d790503620e456a8b40713282b14271f95f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 12:58:58 +0200 Subject: [PATCH 022/211] nuke: adding info knob to backdrop node creator --- openpype/hosts/nuke/plugins/create/create_backdrop.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index e622fd12be..40eaab08cf 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -38,6 +38,8 @@ class CreateBackdrop(NukeCreator): created_node["note_font_size"].setValue(24) created_node["label"].setValue("[{}]".format(node_name)) + self.add_info_knob(created_node) + return created_node def create(self, subset_name, instance_data, pre_create_data): From e9c8144d6edbd6452a50089cf41bb478f147f917 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 20:42:41 +0200 Subject: [PATCH 023/211] nuke: adding apply settings to NukeCreator --- openpype/hosts/nuke/api/plugin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 7cb8bc8b84..4b85334c03 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -201,6 +201,10 @@ class NukeCreator(NewCreator): BoolDef("use_selection", label="Use selection") ] + def apply_settings(self, project_settings, system_settings): + """Method called on initialization of plugin to apply settings.""" + self.creators_settings = project_settings["nuke"]["create"] + class OpenPypeCreator(LegacyCreator): """Pype Nuke Creator class wrapper""" From cab1a09d5fa857fd7b5471600709e3acca513668 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 20:57:05 +0200 Subject: [PATCH 024/211] nuke: adding also active key check in validator --- openpype/hosts/nuke/plugins/publish/validate_knobs.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_knobs.py b/openpype/hosts/nuke/plugins/publish/validate_knobs.py index d44f27791a..1d853f72b5 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_knobs.py +++ b/openpype/hosts/nuke/plugins/publish/validate_knobs.py @@ -62,7 +62,16 @@ class ValidateKnobs(pyblish.api.ContextPlugin): for instance in context: # Filter publisable instances. - if not instance.data["publish"]: + if ( + instance.data.get("publish") + and instance.data["publish"] is False + ): + continue + + if ( + instance.data.get("active") + and instance.data["active"] is False + ): continue # Filter families. From 86e740c43be228f946835890ab9caaebdb23c542 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 20:57:30 +0200 Subject: [PATCH 025/211] nuke: removing print --- openpype/hosts/nuke/plugins/publish/extract_backdrop.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py index e62c715b9c..5166fa4b2c 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py @@ -104,6 +104,3 @@ class ExtractBackdropNode(publish.Extractor): self.log.info("Extracted instance '{}' to: {}".format( instance.name, path)) - - self.log.info("Data {}".format( - instance.data)) From bcac2bd143bcd07517cef7604e7190f0d6c986c4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:13:26 +0200 Subject: [PATCH 026/211] nuke: settings for write attributes --- .../defaults/project_settings/nuke.json | 26 +++++---- .../projects_schema/schema_project_nuke.json | 58 +++++-------------- .../schemas/template_nuke_write_attrs.json | 19 ++++++ 3 files changed, 49 insertions(+), 54 deletions(-) create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_write_attrs.json diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 7b3d07d441..cdb410b378 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -56,12 +56,15 @@ ], "create": { "CreateWriteRender": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", - "defaults": [ + "temp_rendering_path_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", + "default_variants": [ "Main", "Mask" ], - "knobs": [], + "instance_attributes": [ + "reviewable", + "farm_rendering" + ], "prenodes": { "Reformat01": { "nodeclass": "Reformat", @@ -82,27 +85,28 @@ } }, "CreateWritePrerender": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", - "use_range_limit": true, - "defaults": [ + "temp_rendering_path_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", + "default_variants": [ "Key01", "Bg01", "Fg01", "Branch01", "Part01" ], - "reviewable": false, - "knobs": [], + "instance_attributes": [ + "farm_rendering", + "use_range_limit" + ], "prenodes": {} }, "CreateWriteStill": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{ext}", - "defaults": [ + "temp_rendering_path_template": "{work}/renders/nuke/{subset}/{subset}.{ext}", + "default_variants": [ "ImageFrame", "MPFrame", "LayoutFrame" ], - "knobs": [], + "instance_attributes": [], "prenodes": { "FrameHold01": { "nodeclass": "FrameHold", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index c21df7d44d..520985154e 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -97,26 +97,20 @@ "children": [ { "type": "text", - "key": "fpath_template", - "label": "Path template" + "key": "temp_rendering_path_template", + "label": "Temporary rendering path template" }, { "type": "list", - "key": "defaults", - "label": "Subset name defaults", + "key": "default_variants", + "label": "Default variants", "object_type": { "type": "text" } }, { "type": "schema_template", - "name": "template_nuke_knob_inputs", - "template_data": [ - { - "label": "Node knobs", - "key": "knobs" - } - ] + "name": "template_nuke_write_attrs" }, { "key": "prenodes", @@ -160,36 +154,20 @@ "children": [ { "type": "text", - "key": "fpath_template", - "label": "Path template" - }, - { - "type": "boolean", - "key": "use_range_limit", - "label": "Use Frame range limit by default" + "key": "temp_rendering_path_template", + "label": "Temporary rendering path template" }, { "type": "list", - "key": "defaults", - "label": "Subset name defaults", + "key": "default_variants", + "label": "Default variants", "object_type": { "type": "text" } }, - { - "type": "boolean", - "key": "reviewable", - "label": "Add reviewable toggle" - }, { "type": "schema_template", - "name": "template_nuke_knob_inputs", - "template_data": [ - { - "label": "Node knobs", - "key": "knobs" - } - ] + "name": "template_nuke_write_attrs" }, { "key": "prenodes", @@ -233,26 +211,20 @@ "children": [ { "type": "text", - "key": "fpath_template", - "label": "Path template" + "key": "temp_rendering_path_template", + "label": "Temporary rendering path template" }, { "type": "list", - "key": "defaults", - "label": "Subset name defaults", + "key": "default_variants", + "label": "Default variants", "object_type": { "type": "text" } }, { "type": "schema_template", - "name": "template_nuke_knob_inputs", - "template_data": [ - { - "label": "Node knobs", - "key": "knobs" - } - ] + "name": "template_nuke_write_attrs" }, { "key": "prenodes", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_write_attrs.json b/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_write_attrs.json new file mode 100644 index 0000000000..8be48e669d --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_write_attrs.json @@ -0,0 +1,19 @@ +[ + { + "key": "instance_attributes", + "label": "Instance attributes", + "type": "enum", + "multiselection": true, + "enum_items": [ + { + "reviewable": "Reviewable" + }, + { + "farm_rendering": "Farm rendering" + }, + { + "use_range_limit": "Use range limit" + } + ] + } +] From ca6d8bd7123616eb2fdb458761ba4556a95480ef Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:17:30 +0200 Subject: [PATCH 027/211] Nuke adding deprecation warning and adding it to deprecated functions --- openpype/hosts/nuke/api/lib.py | 99 ++++++++++++++++++++----------- openpype/hosts/nuke/api/plugin.py | 6 +- 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 211bab2d80..68f0ca6e35 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -3,6 +3,8 @@ from pprint import pformat import re import json import six +import functools +import warnings import platform import tempfile import contextlib @@ -68,6 +70,51 @@ ROOT_DATA_KNOB = "publish_context" INSTANCE_DATA_KNOB = "publish_instance" +class DeprecatedWarning(DeprecationWarning): + pass + + +def deprecated(new_destination): + """Mark functions as deprecated. + + It will result in a warning being emitted when the function is used. + """ + + func = None + if callable(new_destination): + func = new_destination + new_destination = None + + def _decorator(decorated_func): + if new_destination is None: + warning_message = ( + " Please check content of deprecated function to figure out" + " possible replacement." + ) + else: + warning_message = " Please replace your usage with '{}'.".format( + new_destination + ) + + @functools.wraps(decorated_func) + def wrapper(*args, **kwargs): + warnings.simplefilter("always", DeprecatedWarning) + warnings.warn( + ( + "Call to deprecated function '{}'" + "\nFunction was moved or removed.{}" + ).format(decorated_func.__name__, warning_message), + category=DeprecatedWarning, + stacklevel=4 + ) + return decorated_func(*args, **kwargs) + return wrapper + + if func is None: + return _decorator + return _decorator(func) + + class Context: main_window = None context_label = None @@ -1164,8 +1211,6 @@ def create_write_node( data, input=None, prenodes=None, - review=True, - farm=True, linked_knobs=None, **kwargs ): @@ -1207,35 +1252,26 @@ def create_write_node( ''' prenodes = prenodes or {} - # group node knob overrides - knob_overrides = data.pop("knobs", []) - # filtering variables plugin_name = data["creator"] subset = data["subset"] # get knob settings for write node imageio_writes = get_imageio_node_setting( - node_class=data["nodeclass"], + node_class="Write", plugin_name=plugin_name, subset=subset ) for knob in imageio_writes["knobs"]: if knob["name"] == "file_type": - representation = knob["value"] + ext = knob["value"] - try: - data.update({ - "imageio_writes": imageio_writes, - "representation": representation, - }) - anatomy_filled = format_anatomy(data) - - except Exception as e: - msg = "problem with resolving anatomy template: {}".format(e) - log.error(msg) - nuke.message(msg) + data.update({ + "imageio_writes": imageio_writes, + "ext": ext + }) + anatomy_filled = format_anatomy(data) # build file path to workfiles fdir = str(anatomy_filled["work"]["folder"]).replace("\\", "/") @@ -1244,7 +1280,7 @@ def create_write_node( version=data["version"], subset=data["subset"], frame=data["frame"], - ext=representation + ext=ext ) # create directory @@ -1298,14 +1334,6 @@ def create_write_node( # connect to previous node now_node.setInput(0, prev_node) - # imprinting group node - set_avalon_knob_data(GN, data["avalon"]) - add_publish_knob(GN) - add_rendering_knobs(GN, farm) - - if review: - add_review_knob(GN) - # add divider GN.addKnob(nuke.Text_Knob('', 'Rendering')) @@ -1351,12 +1379,6 @@ def create_write_node( # adding write to read button add_button_clear_rendered(GN, os.path.dirname(fpath)) - # Deadline tab. - add_deadline_tab(GN) - - # open the our Tab as default - GN[_NODE_TAB_NAME].setFlag(0) - # set tile color tile_color = next( iter( @@ -1367,12 +1389,10 @@ def create_write_node( GN["tile_color"].setValue( color_gui_to_int(tile_color)) - # finally add knob overrides - set_node_knobs_from_settings(GN, knob_overrides, **kwargs) - return GN +@deprecated("openpype.hosts.nuke.api.lib.create_write_node") def create_write_node_legacy( name, data, input=None, prenodes=None, review=True, linked_knobs=None, farm=True @@ -1725,6 +1745,7 @@ def color_gui_to_int(color_gui): return int(hex_value, 16) +@deprecated def add_rendering_knobs(node, farm=True): ''' Adds additional rendering knobs to given node @@ -1745,6 +1766,7 @@ def add_rendering_knobs(node, farm=True): return node +@deprecated def add_review_knob(node): ''' Adds additional review knob to given node @@ -1761,7 +1783,9 @@ def add_review_knob(node): return node +@deprecated def add_deadline_tab(node): + # TODO: remove this as it is only linked to legacy create node.addKnob(nuke.Tab_Knob("Deadline")) knob = nuke.Int_Knob("deadlinePriority", "Priority") @@ -1787,7 +1811,10 @@ def add_deadline_tab(node): node.addKnob(knob) +@deprecated def get_deadline_knob_names(): + # TODO: remove this as it is only linked to legacy + # validate_write_deadline_tab return [ "Deadline", "deadlineChunkSize", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 4b85334c03..cb062bc647 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -33,7 +33,8 @@ from .lib import ( get_nuke_imageio_settings, set_node_knobs_from_settings, get_view_process_node, - set_node_data + set_node_data, + deprecated ) from .pipeline import ( list_instances, @@ -138,7 +139,7 @@ class NukeCreator(NewCreator): # make sure subset name is unique if self.check_existing_subset(subset_name, instance_data): raise NukeCreatorError( - ("subset {} is already published with different HDA" + ("subset {} is already published" "definition.").format(subset_name)) try: @@ -736,6 +737,7 @@ class ExporterReviewMov(ExporterReview): return self.data +@deprecated("openpype.hosts.nuke.api.plugin.NukeWriteCreator") class AbstractWriteRender(OpenPypeCreator): """Abstract creator to gather similar implementation for Write creators""" name = "" From 57863b5151287f36d30159520f3f48181dc870f1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:18:26 +0200 Subject: [PATCH 028/211] nuke: fix format anatomy func --- openpype/hosts/nuke/api/lib.py | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 68f0ca6e35..8bc905dfe8 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1082,27 +1082,14 @@ def format_anatomy(data): Return: path (str) ''' - # TODO: perhaps should be nonPublic - anatomy = Anatomy() log.debug("__ anatomy.templates: {}".format(anatomy.templates)) - try: - # TODO: bck compatibility with old anatomy template - padding = int( - anatomy.templates["render"].get( - "frame_padding", - anatomy.templates["render"].get("padding") - ) + padding = int( + anatomy.templates["render"].get( + "frame_padding" ) - except KeyError as e: - msg = ("`padding` key is not in `render` " - "or `frame_padding` on is not available in " - "Anatomy template. Please, add it there and restart " - "the pipeline (padding: \"4\"): `{}`").format(e) - - log.error(msg) - nuke.message(msg) + ) version = data.get("version", None) if not version: @@ -1110,16 +1097,16 @@ def format_anatomy(data): data["version"] = get_version_from_path(file) project_name = anatomy.project_name - asset_name = data["avalon"]["asset"] - task_name = os.environ["AVALON_TASK"] + asset_name = data["asset"] + task_name = data["task"] host_name = os.environ["AVALON_APP"] context_data = get_template_data_with_names( project_name, asset_name, task_name, host_name ) data.update(context_data) data.update({ - "subset": data["avalon"]["subset"], - "family": data["avalon"]["family"], + "subset": data["subset"], + "family": data["family"], "frame": "#" * padding, }) return anatomy.format(data) From 8d0758887ec84f7a0a14ab6d42dfe98c0f7e3e09 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:19:02 +0200 Subject: [PATCH 029/211] nuke: unparent publisher --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index cbe8b547c6..e8fba8ae34 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -233,7 +233,7 @@ def _install_menu(): menu.addSeparator() menu.addCommand( "Publish...", - lambda: host_tools.show_publisher(parent=main_window) + host_tools.show_publisher ) menu.addCommand( "Load...", From 694d1026e8706a3a3f4d343ec27f8c300b4c39eb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:19:23 +0200 Subject: [PATCH 030/211] nuke: add NukeWriteCreator --- openpype/hosts/nuke/api/plugin.py | 128 +++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index cb062bc647..091ef81d0f 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,3 +1,4 @@ +from pprint import pformat import nuke import os @@ -14,7 +15,10 @@ from openpype.client import ( ) from openpype.api import get_current_project_settings -from openpype.lib import BoolDef +from openpype.lib import ( + BoolDef, + EnumDef +) from openpype.pipeline import ( LegacyCreator, LoaderPlugin, @@ -202,9 +206,127 @@ class NukeCreator(NewCreator): BoolDef("use_selection", label="Use selection") ] - def apply_settings(self, project_settings, system_settings): + def get_creator_settings(self, project_settings, settings_key=None): + if not settings_key: + settings_key = self.__class__.__name__ + return project_settings["nuke"]["create"][settings_key] + + +class NukeWriteCreator(NukeCreator): + """Add Publishable Write node""" + + identifier = "create_write" + label = "Create Write" + family = "write" + icon = "sign-out" + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + selected_nodes = nuke.selectedNodes() + if selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one camera node") + self.selected_node = selected_nodes[0] + else: + self.selected_node = None + + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum() + ] + return attr_defs + + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + return attr_defs + + def _get_render_target_enum(self): + rendering_targets = { + "local": "Local machine rendering", + "frames": "Use existing frames" + } + if ("farm_rendering" in self.instance_attributes): + rendering_targets["farm"] = "Farm rendering" + + return EnumDef( + "render_target", + items=rendering_targets, + label="Render target" + ) + + def _get_reviewable_bool(self): + return BoolDef( + "review", + default=("reviewable" in self.instance_attributes), + label="Review" + ) + + def create(self, subset_name, instance_data, pre_create_data): + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + set_node_data( + instance_node, INSTANCE_DATA_KNOB, instance.data_to_store()) + + return instance + + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2]) + + return instance + + def apply_settings( + self, + project_settings, + system_settings, + # anatomy_settings + ): """Method called on initialization of plugin to apply settings.""" - self.creators_settings = project_settings["nuke"]["create"] + + # plugin settings + plugin_settings = self.get_creator_settings(project_settings) + + self.log.debug("___________________") + self.log.debug(pformat(plugin_settings)) + + # individual attributes + self.instance_attributes = plugin_settings[ + "instance_attributes"] + self.prenodes = plugin_settings["prenodes"] + self.default_variants = plugin_settings["default_variants"] + self.temp_rendering_path_template = plugin_settings[ + "temp_rendering_path_template"] class OpenPypeCreator(LegacyCreator): From 36672bb82704fbd2e2fdf698d1368d92dba7b3d6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:19:42 +0200 Subject: [PATCH 031/211] Nuke: add camera creator --- .../nuke/plugins/create/create_camera.py | 106 +++++++++++------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index 3b13c80dc4..0b538d0088 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -1,55 +1,75 @@ import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateCamera(plugin.OpenPypeCreator): - """Add Publishable Backdrop""" +class CreateCamera(NukeCreator): + """Add Publishable Camera""" - name = "camera" + identifier = "create_camera" label = "Create 3d Camera" family = "camera" icon = "camera" - defaults = ["Main"] - def __init__(self, *args, **kwargs): - super(CreateCamera, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xff9100ff" - return + # plugin attributes + node_color = "0xff9100ff" - def process(self): - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes - - if len(nodes) >= 1: - # loop selected nodes - for n in nodes: - data = self.data.copy() - if len(nodes) > 1: - # rename subset name only if more - # then one node are selected - subset = self.family + n["name"].value().capitalize() - data["subset"] = subset - - # change node color - n["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - set_avalon_knob_data(n, data) - return True + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + created_node = self.selected_nodes[0] else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return + created_node = nuke.createNode("Camera2") + + created_node["tile_color"].setValue( + int(self.node_color, 16)) + + created_node["name"].setValue(node_name) + + self.add_info_knob(created_node) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published with different HDA" + "definition.").format(subset_name)) + + instance = super(CreateCamera, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(self.selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one camera node") else: - # if selected is off then create one node - camera_node = nuke.createNode("Camera2") - camera_node["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - instance = set_avalon_knob_data(camera_node, self.data) - return instance + self.selected_nodes = [] + + self.log.debug("Selection is: {}".format(self.selected_nodes)) + + def apply_settings(self, project_settings, system_settings): + """Method called on initialization of plugin to apply settings.""" + + # only selected keys ideally + # settings = self.get_creator_settings(project_settings) + + # self.key = settings["key"] + pass \ No newline at end of file From 5bafa21ea84da086f078999e4ee67a9f4d181a20 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:20:19 +0200 Subject: [PATCH 032/211] nuke: refactor create write render to new publisher --- .../plugins/create/create_write_render.py | 139 +++++++++--------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 23846c0332..3d7f5b8e37 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -1,86 +1,89 @@ +from pprint import pformat import nuke +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + UILabelDef +) from openpype.hosts.nuke.api import plugin from openpype.hosts.nuke.api.lib import ( - create_write_node, create_write_node_legacy) + create_write_node) -class CreateWriteRender(plugin.AbstractWriteRender): - # change this to template preset - name = "WriteRender" +class CreateWriteRender(plugin.NukeWriteCreator): + identifier = "create_write_render" label = "Create Write Render" - hosts = ["nuke"] - n_class = "Write" family = "render" icon = "sign-out" - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{frame}.{ext}" - defaults = ["Main", "Mask"] - prenodes = { - "Reformat01": { - "nodeclass": "Reformat", - "dependent": None, - "knobs": [ - { - "type": "text", - "name": "resize", - "value": "none" - }, - { - "type": "bool", - "name": "black_outside", - "value": True - } - ] - } - } + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum() + ] + return attr_defs - def __init__(self, *args, **kwargs): - super(CreateWriteRender, self).__init__(*args, **kwargs) + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + if "farm_rendering" in self.instance_attributes: + attr_defs.extend([ + UISeparatorDef(), + UILabelDef("Farm rendering attributes"), + BoolDef("suspended_publish", label="Suspended publishing"), + NumberDef( + "farm_priority", + label="Priority", + minimum=1, + maximum=99, + default=50 + ), + NumberDef( + "farm_chunk", + label="Chunk size", + minimum=1, + maximum=99, + default=10 + ), + NumberDef( + "farm_concurency", + label="Concurent tasks", + minimum=1, + maximum=10, + default=1 + ) + ]) + return attr_defs - def _create_write_node(self, selected_node, inputs, outputs, write_data): + def create_instance_node(self, subset_name, instance_data): # add fpath_template - write_data["fpath_template"] = self.fpath_template + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } + + write_data.update(instance_data) - # add reformat node to cut off all outside of format bounding box # get width and height - try: - width, height = (selected_node.width(), selected_node.height()) - except AttributeError: + if self.selected_node: + width, height = ( + self.selected_node.width(), self.selected_node.height()) + else: actual_format = nuke.root().knob('format').value() width, height = (actual_format.width(), actual_format.height()) - if not self.is_legacy(): - return create_write_node( - self.data["subset"], - write_data, - input=selected_node, - prenodes=self.prenodes, - **{ - "width": width, - "height": height - } - ) - else: - _prenodes = [ - { - "name": "Reformat01", - "class": "Reformat", - "knobs": [ - ("resize", 0), - ("black_outside", 1), - ], - "dependent": None - } - ] - - return create_write_node_legacy( - self.data["subset"], - write_data, - input=selected_node, - prenodes=_prenodes - ) - - def _modify_write_node(self, write_node): - return write_node + return create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + **{ + "width": width, + "height": height + } + ) From 3a02562b7aa8d401216af3fefab189ab78cad510 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:08:13 +0200 Subject: [PATCH 033/211] Nuke: adding missing api functions --- openpype/hosts/nuke/api/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 8b18d4bc3b..47a62aa3e0 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -11,6 +11,7 @@ from .command import ( ) from .plugin import ( NukeCreator, + NukeWriteCreator, NukeCreatorError, OpenPypeCreator ) @@ -40,7 +41,8 @@ from .lib import ( convert_knob_value_to_correct_type, get_node_data, set_node_data, - update_node_data + update_node_data, + create_write_node ) from .utils import ( colorspace_exists_on_node, @@ -58,6 +60,7 @@ __all__ = ( "viewer_update_and_undo_stop", "NukeCreator", + "NukeWriteCreator", "NukeCreatorError", "OpenPypeCreator", "NukeHost", @@ -85,6 +88,7 @@ __all__ = ( "get_node_data", "set_node_data", "update_node_data", + "create_write_node", "colorspace_exists_on_node", "get_colorspace_list" From 7635528199e89bf8a87b76d8ca24f6d55d6ee2a8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:08:38 +0200 Subject: [PATCH 034/211] nuke: cosmetic changes --- openpype/hosts/nuke/api/lib.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 8bc905dfe8..a9e12c0f4d 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1366,6 +1366,8 @@ def create_write_node( # adding write to read button add_button_clear_rendered(GN, os.path.dirname(fpath)) + GN.addKnob(nuke.Text_Knob('', '')) + # set tile color tile_color = next( iter( From 96b6f87a922a5ab1ca32233a276ea7ea174d9f5e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:09:06 +0200 Subject: [PATCH 035/211] nuke: make the info text less aggressive --- openpype/hosts/nuke/api/plugin.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 091ef81d0f..32cdaf9c86 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -60,9 +60,10 @@ class NukeCreator(NewCreator): # add info text info_knob = nuke.Text_Knob("OP_info", "") info_knob.setValue(""" -

Do not erase manually !

+

This node is maintained by OpenPype Publisher.

-

We recomand to remove it from the Publisher gui.

+

To remove it use Publisher gui.

+
""") node.addKnob(info_knob) @@ -302,9 +303,8 @@ class NukeWriteCreator(NukeCreator): six.reraise( NukeCreatorError, NukeCreatorError("Creator error: {}".format(er)), - sys.exc_info()[2]) - - return instance + sys.exc_info()[2] + ) def apply_settings( self, From d7037a7b354e49fde1135e6ad100fae14f768bcb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:09:33 +0200 Subject: [PATCH 036/211] nuke: add create function into write render creator --- .../plugins/create/create_write_render.py | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 3d7f5b8e37..85aaedb208 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -1,18 +1,20 @@ -from pprint import pformat import nuke +import sys +import six +from openpype.pipeline import ( + CreatedInstance +) from openpype.lib import ( BoolDef, NumberDef, UISeparatorDef, UILabelDef ) -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node) +from openpype.hosts.nuke import api as napi -class CreateWriteRender(plugin.NukeWriteCreator): +class CreateWriteRender(napi.NukeWriteCreator): identifier = "create_write_render" label = "Create Write Render" family = "render" @@ -77,7 +79,7 @@ class CreateWriteRender(plugin.NukeWriteCreator): actual_format = nuke.root().knob('format').value() width, height = (actual_format.width(), actual_format.height()) - return create_write_node( + created_node = napi.create_write_node( subset_name, write_data, input=self.selected_node, @@ -87,3 +89,48 @@ class CreateWriteRender(plugin.NukeWriteCreator): "height": height } ) + self.add_info_knob(created_node) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) From 0e0df359d69c7aea92834a93d014fe9e072b3f9e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:32:30 +0200 Subject: [PATCH 037/211] nuke: adding relinking function --- openpype/hosts/nuke/api/plugin.py | 20 +++++++++++++++++++ .../plugins/create/create_write_render.py | 2 ++ 2 files changed, 22 insertions(+) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 32cdaf9c86..340ccc7abb 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -221,6 +221,26 @@ class NukeWriteCreator(NukeCreator): family = "write" icon = "sign-out" + def integrate_links(self, node, outputs=True): + # skip if no selection + if not self.selected_node: + return + + # collect dependencies + input_nodes = [self.selected_node] + dependent_nodes = self.selected_node.dependent() if outputs else [] + + # relinking to collected connections + for i, input in enumerate(input_nodes): + node.setInput(i, input) + + # make it nicer in graph + node.autoplace() + + # relink also dependent nodes + for dep_nodes in dependent_nodes: + dep_nodes.setInput(0, node) + def set_selected_nodes(self, pre_create_data): if pre_create_data.get("use_selection"): selected_nodes = nuke.selectedNodes() diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 85aaedb208..560b9e0c36 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -91,6 +91,8 @@ class CreateWriteRender(napi.NukeWriteCreator): ) self.add_info_knob(created_node) + self.integrate_links(created_node, outputs=False) + return created_node def create(self, subset_name, instance_data, pre_create_data): From 4aedaa975e8513b9b6aee9e70e23105c15b97bd9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 16:42:39 +0200 Subject: [PATCH 038/211] Nuke refactory write still creator --- openpype/hosts/nuke/api/lib.py | 1 - .../nuke/plugins/create/create_write_still.py | 193 +++++++++++------- 2 files changed, 115 insertions(+), 79 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index a9e12c0f4d..b09a164ac1 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1680,7 +1680,6 @@ def set_node_knobs_from_settings(node, knob_settings, **kwargs): _knob_value = template.format( **kwargs ) - log.debug("__ knob_value0: {}".format(_knob_value)) except KeyError as msg: log.warning("__ msg: {}".format(msg)) raise KeyError(msg) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index bb08e8c2c6..7627bc3d9f 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -1,96 +1,133 @@ import nuke +import sys +import six -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node, - create_write_node_legacy, - get_created_node_imageio_setting_legacy +from openpype.pipeline import ( + CreatedInstance ) - -# HACK: just to disable still image on projects which -# are not having anatomy imageio preset for CreateWriteStill -# TODO: remove this code as soon as it will be obsolete -imageio_writes = get_created_node_imageio_setting_legacy( - "Write", - "CreateWriteStill", - "stillMain" +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + EnumDef ) -print(imageio_writes["knobs"]) +from openpype.hosts.nuke import api as napi -class CreateWriteStill(plugin.AbstractWriteRender): - # change this to template preset - name = "WriteStillFrame" - label = "Create Write Still Image" - hosts = ["nuke"] - n_class = "Write" +class CreateWriteStill(napi.NukeWriteCreator): + identifier = "create_write_still" + label = "Create Write Still Frame" family = "still" - icon = "image" + icon = "sign-out" - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{ext}" - defaults = [ - "ImageFrame", - "MPFrame", - "LayoutFrame" - ] - prenodes = { - "FrameHold01": { - "nodeclass": "FrameHold", - "dependent": None, - "knobs": [ - { - "type": "formatable", - "name": "first_frame", - "template": "{frame}", - "to_type": "number" - } - ] + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum(), + UISeparatorDef(), + self._get_frame_source_number() + ] + return attr_defs + + def _get_render_target_enum(self): + rendering_targets = { + "local": "Local machine rendering", + "frames": "Use existing frames" } - } - def __init__(self, *args, **kwargs): - super(CreateWriteStill, self).__init__(*args, **kwargs) + return EnumDef( + "render_target", + items=rendering_targets, + label="Render target" + ) - def _create_write_node(self, selected_node, inputs, outputs, write_data): + def _get_frame_source_number(self): + return NumberDef( + "active_frame", + label="Active frame", + default=nuke.frame() + ) + + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + return attr_defs + + def create_instance_node(self, subset_name, instance_data): # add fpath_template - write_data["fpath_template"] = self.fpath_template + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } - if not self.is_legacy(): - return create_write_node( - self.name, - write_data, - input=selected_node, - review=False, - prenodes=self.prenodes, - farm=False, - linked_knobs=["channels", "___", "first", "last", "use_limit"], - **{ - "frame": nuke.frame() - } - ) - else: - _prenodes = [ - { - "name": "FrameHold01", - "class": "FrameHold", - "knobs": [ - ("first_frame", nuke.frame()) - ], - "dependent": None - } - ] - return create_write_node_legacy( - self.name, - write_data, - input=selected_node, - review=False, - prenodes=_prenodes, - farm=False, - linked_knobs=["channels", "___", "first", "last", "use_limit"] + write_data.update(instance_data) + + created_node = napi.create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + linked_knobs=["channels", "___", "first", "last", "use_limit"], + **{ + "frame": nuke.frame() + } + ) + self.add_info_knob(created_node) + + self._add_frame_range_limit(created_node) + + self.integrate_links(created_node, outputs=False) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + subset_name = subset_name.format(**pre_create_data) + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self ) - def _modify_write_node(self, write_node): + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) + + def _add_frame_range_limit(self, write_node): write_node.begin() for n in nuke.allNodes(): # get write node From d8df51e49f589ccfa951fa92f511aa178c2a859b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:21:17 +0200 Subject: [PATCH 039/211] nuke: adding expression value knob to settings template --- openpype/hosts/nuke/api/lib.py | 7 +++++++ .../schemas/template_nuke_knob_inputs.json | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index b09a164ac1..4478633198 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1672,6 +1672,13 @@ def set_node_knobs_from_settings(node, knob_settings, **kwargs): if knob_name not in node.knobs(): continue + if knob_type == "expression": + knob_expression = knob["expression"] + node[knob_name].setExpression( + knob_expression + ) + continue + # first deal with formatable knob settings if knob_type == "formatable": template = knob["template"] diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_knob_inputs.json b/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_knob_inputs.json index 52a14e0636..c9dee8681a 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_knob_inputs.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_knob_inputs.json @@ -28,6 +28,22 @@ } ] }, + { + "key": "expression", + "label": "Expression", + "children": [ + { + "type": "text", + "key": "name", + "label": "Name" + }, + { + "type": "text", + "key": "expression", + "label": "Expression" + } + ] + }, { "key": "formatable", "label": "Formate from template", From 4b42d55ce1acac083aa95ee7babe2467fe83b32e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:22:05 +0200 Subject: [PATCH 040/211] nuke: improving still write creator settings --- openpype/settings/defaults/project_settings/nuke.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index cdb410b378..783b42348c 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -106,17 +106,18 @@ "MPFrame", "LayoutFrame" ], - "instance_attributes": [], + "instance_attributes": [ + "use_range_limit" + ], "prenodes": { "FrameHold01": { "nodeclass": "FrameHold", "dependent": "", "knobs": [ { - "type": "formatable", + "type": "expression", "name": "first_frame", - "template": "{frame}", - "to_type": "number" + "expression": "parent.first" } ] } From 63c46e10112392daaccea1f3fd0cde65305729b9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:22:43 +0200 Subject: [PATCH 041/211] nuke: adding optional use frame range to plugin --- openpype/hosts/nuke/plugins/create/create_write_still.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index 7627bc3d9f..a254df4b62 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -56,13 +56,16 @@ class CreateWriteStill(napi.NukeWriteCreator): return attr_defs def create_instance_node(self, subset_name, instance_data): + linked_knobs_ = [] + if "use_range_limit" in self.instance_attributes: + linked_knobs_ = ["channels", "___", "first", "last", "use_limit"] + # add fpath_template write_data = { "creator": self.__class__.__name__, "subset": subset_name, "fpath_template": self.temp_rendering_path_template } - write_data.update(instance_data) created_node = napi.create_write_node( @@ -70,7 +73,7 @@ class CreateWriteStill(napi.NukeWriteCreator): write_data, input=self.selected_node, prenodes=self.prenodes, - linked_knobs=["channels", "___", "first", "last", "use_limit"], + linked_knobs=linked_knobs_, **{ "frame": nuke.frame() } @@ -137,6 +140,6 @@ class CreateWriteStill(napi.NukeWriteCreator): w_node["use_limit"].setValue(True) w_node["first"].setValue(nuke.frame()) - w_node["last"].setValue(nuke.frame()) + w_node["last"].setExpression("first") return write_node From 5946ea708c63bc317419e3f3ea8212f558091caf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:24:01 +0200 Subject: [PATCH 042/211] nuke clear printing --- openpype/hosts/nuke/api/plugin.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 340ccc7abb..585841ece8 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -337,9 +337,6 @@ class NukeWriteCreator(NukeCreator): # plugin settings plugin_settings = self.get_creator_settings(project_settings) - self.log.debug("___________________") - self.log.debug(pformat(plugin_settings)) - # individual attributes self.instance_attributes = plugin_settings[ "instance_attributes"] From 82e18450ce55abf20d3967d53896c95cbd333b84 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:50:49 +0200 Subject: [PATCH 043/211] nuke: refectory prerender write creator --- .../plugins/create/create_write_prerender.py | 180 ++++++++++++++---- .../nuke/plugins/create/create_write_still.py | 3 + 2 files changed, 141 insertions(+), 42 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index fec97167fb..976b3261d9 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -1,56 +1,153 @@ import nuke +import sys +import six -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node, create_write_node_legacy) +from openpype.pipeline import ( + CreatedInstance +) +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + UILabelDef +) +from openpype.hosts.nuke import api as napi -class CreateWritePrerender(plugin.AbstractWriteRender): - # change this to template preset - name = "WritePrerender" +class CreateWritePrerender(napi.NukeWriteCreator): + identifier = "create_write_prerender" label = "Create Write Prerender" - hosts = ["nuke"] - n_class = "Write" family = "prerender" icon = "sign-out" - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{frame}.{ext}" - defaults = ["Key01", "Bg01", "Fg01", "Branch01", "Part01"] - reviewable = False - use_range_limit = True + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum() + ] + return attr_defs - def __init__(self, *args, **kwargs): - super(CreateWritePrerender, self).__init__(*args, **kwargs) + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + if "farm_rendering" in self.instance_attributes: + attr_defs.extend([ + UISeparatorDef(), + UILabelDef("Farm rendering attributes"), + BoolDef("suspended_publish", label="Suspended publishing"), + NumberDef( + "farm_priority", + label="Priority", + minimum=1, + maximum=99, + default=50 + ), + NumberDef( + "farm_chunk", + label="Chunk size", + minimum=1, + maximum=99, + default=10 + ), + NumberDef( + "farm_concurency", + label="Concurent tasks", + minimum=1, + maximum=10, + default=1 + ) + ]) + return attr_defs + + def create_instance_node(self, subset_name, instance_data): + linked_knobs_ = [] + if "use_range_limit" in self.instance_attributes: + linked_knobs_ = ["channels", "___", "first", "last", "use_limit"] - def _create_write_node(self, selected_node, inputs, outputs, write_data): # add fpath_template - write_data["fpath_template"] = self.fpath_template - write_data["use_range_limit"] = self.use_range_limit - write_data["frame_range"] = ( - nuke.root()["first_frame"].value(), - nuke.root()["last_frame"].value() + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } + + write_data.update(instance_data) + + # get width and height + if self.selected_node: + width, height = ( + self.selected_node.width(), self.selected_node.height()) + else: + actual_format = nuke.root().knob('format').value() + width, height = (actual_format.width(), actual_format.height()) + + created_node = napi.create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + linked_knobs=linked_knobs_, + **{ + "width": width, + "height": height + } + ) + self.add_info_knob(created_node) + + self._add_frame_range_limit(created_node) + + self.integrate_links(created_node, outputs=False) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data ) - if not self.is_legacy(): - return create_write_node( - self.data["subset"], - write_data, - input=selected_node, - review=self.reviewable, - linked_knobs=["channels", "___", "first", "last", "use_limit"] - ) - else: - return create_write_node_legacy( - self.data["subset"], - write_data, - input=selected_node, - review=self.reviewable, - linked_knobs=["channels", "___", "first", "last", "use_limit"] + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self ) - def _modify_write_node(self, write_node): - # open group node + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) + + def _add_frame_range_limit(self, write_node): + if "use_range_limit" not in self.instance_attributes: + return + write_node.begin() for n in nuke.allNodes(): # get write node @@ -58,9 +155,8 @@ class CreateWritePrerender(plugin.AbstractWriteRender): w_node = n write_node.end() - if self.use_range_limit: - w_node["use_limit"].setValue(True) - w_node["first"].setValue(nuke.root()["first_frame"].value()) - w_node["last"].setValue(nuke.root()["last_frame"].value()) + w_node["use_limit"].setValue(True) + w_node["first"].setValue(nuke.root()["first_frame"].value()) + w_node["last"].setValue(nuke.root()["last_frame"].value()) return write_node diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index a254df4b62..e77c51e9be 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -131,6 +131,9 @@ class CreateWriteStill(napi.NukeWriteCreator): ) def _add_frame_range_limit(self, write_node): + if "use_range_limit" not in self.instance_attributes: + return + write_node.begin() for n in nuke.allNodes(): # get write node From 42e993c0bb3c3a2e7c2d1746264e8c837c533ce4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 14:08:00 +0200 Subject: [PATCH 044/211] nuke: adding function for passing attributes from pre create to instance --- openpype/hosts/nuke/api/plugin.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 585841ece8..a509630fb7 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -53,6 +53,19 @@ class NukeCreatorError(CreatorError): class NukeCreator(NewCreator): selected_nodes = [] + def pass_pre_attributes_to_instance( + self, + instance_data, + pre_create_data, + keys=None + ): + if not keys: + keys = pre_create_data.keys() + + creator_attrs = instance_data["creator_attributes"] = {} + for pass_key in keys: + creator_attrs[pass_key] = pre_create_data[pass_key] + def add_info_knob(self, node): if "OP_info" in node.knobs().keys(): return From a68f74a37b6b06f94ce754ca36abf0201744abda Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 14:08:24 +0200 Subject: [PATCH 045/211] nuke: updating write creators --- .../plugins/create/create_write_prerender.py | 17 +++++++++-- .../plugins/create/create_write_render.py | 14 ++++++++- .../nuke/plugins/create/create_write_still.py | 29 +++++++++++++++---- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index 976b3261d9..1ce30379ad 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -22,7 +22,11 @@ class CreateWritePrerender(napi.NukeWriteCreator): def get_pre_create_attr_defs(self): attr_defs = [ - BoolDef("use_selection", label="Use selection"), + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), self._get_render_target_enum() ] return attr_defs @@ -98,11 +102,20 @@ class CreateWritePrerender(napi.NukeWriteCreator): self._add_frame_range_limit(created_node) - self.integrate_links(created_node, outputs=False) + self.integrate_links(created_node, outputs=True) return created_node def create(self, subset_name, instance_data, pre_create_data): + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "render_target" + ] + ) + # make sure selected nodes are added self.set_selected_nodes(pre_create_data) diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 560b9e0c36..89696f55e0 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -22,7 +22,11 @@ class CreateWriteRender(napi.NukeWriteCreator): def get_pre_create_attr_defs(self): attr_defs = [ - BoolDef("use_selection", label="Use selection"), + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), self._get_render_target_enum() ] return attr_defs @@ -96,6 +100,14 @@ class CreateWriteRender(napi.NukeWriteCreator): return created_node def create(self, subset_name, instance_data, pre_create_data): + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "render_target" + ] + ) # make sure selected nodes are added self.set_selected_nodes(pre_create_data) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index e77c51e9be..b3a096a5ba 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -22,7 +22,11 @@ class CreateWriteStill(napi.NukeWriteCreator): def get_pre_create_attr_defs(self): attr_defs = [ - BoolDef("use_selection", label="Use selection"), + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), self._get_render_target_enum(), UISeparatorDef(), self._get_frame_source_number() @@ -80,15 +84,25 @@ class CreateWriteStill(napi.NukeWriteCreator): ) self.add_info_knob(created_node) - self._add_frame_range_limit(created_node) + self._add_frame_range_limit(created_node, instance_data) - self.integrate_links(created_node, outputs=False) + self.integrate_links(created_node, outputs=True) return created_node def create(self, subset_name, instance_data, pre_create_data): subset_name = subset_name.format(**pre_create_data) + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "active_frame", + "render_target" + ] + ) + # make sure selected nodes are added self.set_selected_nodes(pre_create_data) @@ -100,7 +114,7 @@ class CreateWriteStill(napi.NukeWriteCreator): instance_node = self.create_instance_node( subset_name, - instance_data + instance_data, ) try: @@ -130,10 +144,13 @@ class CreateWriteStill(napi.NukeWriteCreator): sys.exc_info()[2] ) - def _add_frame_range_limit(self, write_node): + def _add_frame_range_limit(self, write_node, instance_data): if "use_range_limit" not in self.instance_attributes: return + active_frame = ( + instance_data["creator_attributes"].get("active_frame")) + write_node.begin() for n in nuke.allNodes(): # get write node @@ -142,7 +159,7 @@ class CreateWriteStill(napi.NukeWriteCreator): write_node.end() w_node["use_limit"].setValue(True) - w_node["first"].setValue(nuke.frame()) + w_node["first"].setValue(active_frame or nuke.frame()) w_node["last"].setExpression("first") return write_node From 519642b6c5d7dba2456b4dbb0112c0262a2b5f06 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 15:21:21 +0200 Subject: [PATCH 046/211] nuke: two way compatibility for getting node from instance --- openpype/hosts/nuke/api/__init__.py | 4 +++- openpype/hosts/nuke/api/plugin.py | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 47a62aa3e0..156b3f0de0 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -13,7 +13,8 @@ from .plugin import ( NukeCreator, NukeWriteCreator, NukeCreatorError, - OpenPypeCreator + OpenPypeCreator, + get_instance_node ) from .pipeline import ( NukeHost, @@ -64,6 +65,7 @@ __all__ = ( "NukeCreatorError", "OpenPypeCreator", "NukeHost", + "get_instance_node", "ls", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index a509630fb7..193c2e8c2d 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,4 +1,3 @@ -from pprint import pformat import nuke import os @@ -407,6 +406,15 @@ class OpenPypeCreator(LegacyCreator): return instance +def get_instance_node(instance): + # new publisher way + if instance.data.get("transientData"): + return instance.data["transientData"]["node"] + else: + # or backward compatible + return instance[0] + + def get_review_presets_config(): settings = get_current_project_settings() review_profiles = ( From 61068436c418513cf0399123a2ea93d9e7c9b195 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 15:22:04 +0200 Subject: [PATCH 047/211] nuke: two way compatibility for publish plugins getting instance node and child nodes --- .../nuke/plugins/publish/collect_backdrop.py | 9 ++------ .../nuke/plugins/publish/collect_gizmo.py | 5 ++--- .../nuke/plugins/publish/collect_model.py | 7 +++--- .../nuke/plugins/publish/collect_reads.py | 9 ++++---- .../plugins/publish/collect_slate_node.py | 3 ++- .../nuke/plugins/publish/extract_gizmo.py | 6 +++-- .../nuke/plugins/publish/extract_model.py | 6 +++-- .../plugins/publish/extract_render_local.py | 6 ++++- .../nuke/plugins/publish/extract_thumbnail.py | 12 ++++------ .../nuke/plugins/publish/precollect_writes.py | 7 +++++- .../plugins/publish/validate_asset_name.py | 9 ++++---- .../nuke/plugins/publish/validate_backdrop.py | 10 ++++----- .../nuke/plugins/publish/validate_gizmo.py | 8 +++---- .../publish/validate_output_resolution.py | 20 ++++++++++++----- .../plugins/publish/validate_read_legacy.py | 22 +++++++++---------- .../publish/validate_rendered_frames.py | 7 ++++-- .../plugins/publish/validate_write_legacy.py | 6 ++--- .../plugins/publish/validate_write_nodes.py | 19 ++++++++++++---- 18 files changed, 99 insertions(+), 72 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 688b1054ab..dcabedf231 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -1,6 +1,7 @@ from pprint import pformat import pyblish.api from openpype.hosts.nuke.api import lib as pnlib +from openpype.hosts.nuke import api as napi import nuke @@ -17,12 +18,7 @@ class CollectBackdrops(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug(pformat(instance.data)) - # new publisher way - if instance.data.get("transientData"): - bckn = instance.data["transientData"]["node"] - else: - # or backward compatible - bckn = instance[0] + bckn = napi.get_instance_node(instance) # define size of the backdrop left = bckn.xpos() @@ -91,5 +87,4 @@ class CollectBackdrops(pyblish.api.InstancePlugin): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Backdrop content collected: `{}`".format(instance[:])) self.log.info("Backdrop instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 3db26096ae..755c196f8e 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -1,4 +1,5 @@ import pyblish.api +from openpype.hosts.nuke import api as napi import nuke @@ -13,8 +14,7 @@ class CollectGizmo(pyblish.api.InstancePlugin): families = ["gizmo"] def process(self, instance): - - grpn = instance[0] + grpn = napi.get_instance_node(instance) # add family to familiess instance.data["families"].insert(0, instance.data["family"]) @@ -46,5 +46,4 @@ class CollectGizmo(pyblish.api.InstancePlugin): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Gizmo content collected: `{}`".format(instance[:])) self.log.info("Gizmo instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index 5fca240553..253121ffd4 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -1,6 +1,6 @@ import pyblish.api import nuke - +from openpype.hosts.nuke import api as napi @pyblish.api.log class CollectModel(pyblish.api.InstancePlugin): @@ -14,12 +14,12 @@ class CollectModel(pyblish.api.InstancePlugin): def process(self, instance): - grpn = instance[0] + geo_node = napi.get_instance_node(instance) # add family to familiess instance.data["families"].insert(0, instance.data["family"]) # make label nicer - instance.data["label"] = grpn.name() + instance.data["label"] = geo_node.name() # Get frame range handle_start = instance.context.data["handleStart"] @@ -45,5 +45,4 @@ class CollectModel(pyblish.api.InstancePlugin): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Model content collected: `{}`".format(instance[:])) self.log.info("Model instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index b79d9646d5..7390ec6884 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -5,6 +5,7 @@ import pyblish.api from openpype.client import get_asset_by_name from openpype.pipeline import legacy_io +from openpype.hosts.nuke import api as napi @pyblish.api.log @@ -17,6 +18,8 @@ class CollectNukeReads(pyblish.api.InstancePlugin): families = ["source"] def process(self, instance): + node = napi.get_instance_node(instance) + project_name = legacy_io.active_project() asset_name = legacy_io.Session["AVALON_ASSET"] asset_doc = get_asset_by_name(project_name, asset_name) @@ -25,7 +28,6 @@ class CollectNukeReads(pyblish.api.InstancePlugin): self.log.debug("checking instance: {}".format(instance)) - node = instance[0] if node.Class() != "Read": return @@ -99,10 +101,7 @@ class CollectNukeReads(pyblish.api.InstancePlugin): } instance.data["representations"].append(representation) - transfer = False - if "publish" in node.knobs(): - transfer = node["publish"] - + transfer = node["publish"] if "publish" in node.knobs() else False instance.data['transfer'] = transfer # Add version data to instance diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index bfe32d8fd1..0a98bcf973 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -1,4 +1,5 @@ import pyblish.api +from openpype.hosts.nuke import api as napi import nuke @@ -11,7 +12,7 @@ class CollectSlate(pyblish.api.InstancePlugin): families = ["render", "render.local", "render.farm"] def process(self, instance): - node = instance[0] + node = napi.get_instance_node(instance) slate = next((n for n in nuke.allNodes() if "slate" in n.name().lower() diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index 3047ad6724..a3df497893 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -4,6 +4,7 @@ import nuke import pyblish.api from openpype.pipeline import publish +from openpype.hosts.nuke import api as napi from openpype.hosts.nuke.api import utils as pnutils from openpype.hosts.nuke.api.lib import ( maintained_selection, @@ -24,8 +25,9 @@ class ExtractGizmo(publish.Extractor): families = ["gizmo"] def process(self, instance): - tmp_nodes = list() - orig_grpn = instance[0] + tmp_nodes = [] + orig_grpn = napi.get_instance_node(instance) + # Define extract output file path stagingdir = self.staging_dir(instance) filename = "{0}.nk".format(instance.name) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index d82cb3110b..5ca617f147 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -3,6 +3,7 @@ from pprint import pformat import nuke import pyblish.api +from openpype.hosts.nuke import api as napi from openpype.pipeline import publish from openpype.hosts.nuke.api.lib import ( maintained_selection, @@ -36,8 +37,9 @@ class ExtractModel(publish.Extractor): self.log.info("instance.data: `{}`".format( pformat(instance.data))) - rm_nodes = list() - model_node = instance[0] + rm_nodes = [] + model_node = napi.get_instance_node(instance) + self.log.info("Crating additional nodes") subset = instance.data["subset"] staging_dir = self.staging_dir(instance) diff --git a/openpype/hosts/nuke/plugins/publish/extract_render_local.py b/openpype/hosts/nuke/plugins/publish/extract_render_local.py index 843d588786..811b2d4ffb 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_render_local.py +++ b/openpype/hosts/nuke/plugins/publish/extract_render_local.py @@ -23,9 +23,13 @@ class NukeRenderLocal(publish.Extractor): def process(self, instance): families = instance.data["families"] + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": node = x diff --git a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py index 19eae9638b..dfb1b38284 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py @@ -4,11 +4,7 @@ import nuke import pyblish.api from openpype.pipeline import publish -from openpype.hosts.nuke.api import ( - maintained_selection, - get_view_process_node -) - +from openpype.hosts.nuke import api as napi if sys.version_info[0] >= 3: unicode = str @@ -38,7 +34,7 @@ class ExtractThumbnail(publish.Extractor): if "render.farm" in instance.data["families"]: return - with maintained_selection(): + with napi.maintained_selection(): self.log.debug("instance: {}".format(instance)) self.log.debug("instance.data[families]: {}".format( instance.data["families"])) @@ -69,7 +65,7 @@ class ExtractThumbnail(publish.Extractor): bake_viewer_input_process_node = kwargs[ "bake_viewer_input_process"] - node = instance[0] # group node + node = napi.get_instance_node(instance) # group node self.log.info("Creating staging dir...") if "representations" not in instance.data: @@ -144,7 +140,7 @@ class ExtractThumbnail(publish.Extractor): if bake_viewer_process: if bake_viewer_input_process_node: # get input process and connect it to baking - ipn = get_view_process_node() + ipn = napi.get_view_process_node() if ipn is not None: ipn.setInput(0, previous_node) previous_node = ipn diff --git a/openpype/hosts/nuke/plugins/publish/precollect_writes.py b/openpype/hosts/nuke/plugins/publish/precollect_writes.py index 17c4bc30cf..10eeb91644 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/precollect_writes.py @@ -27,8 +27,13 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): _families_test = [instance.data["family"]] + instance.data["families"] self.log.debug("_families_test: {}".format(_families_test)) + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": node = x diff --git a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py index 52731140ff..0d64da074e 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py +++ b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py @@ -6,7 +6,7 @@ import nuke import pyblish.api import openpype.hosts.nuke.api.lib as nlib -import openpype.hosts.nuke.api as nuke_api +from openpype.hosts.nuke import api as napi from openpype.pipeline.publish import ( ValidateContentsOrder, PublishXmlValidationError, @@ -85,8 +85,8 @@ class RepairSelectInvalidInstances(pyblish.api.Action): context_asset = context.data["assetEntity"]["name"] for instance in instances: - origin_node = instance[0] - nuke_api.lib.recreate_instance( + origin_node = napi.get_instance_node(instance) + napi.lib.recreate_instance( origin_node, avalon_data={"asset": context_asset} ) @@ -112,6 +112,7 @@ class ValidateCorrectAssetName(pyblish.api.InstancePlugin): def process(self, instance): asset = instance.data.get("asset") context_asset = instance.context.data["assetEntity"]["name"] + node = napi.get_instance_node(instance) msg = ( "Instance `{}` has wrong shot/asset name:\n" @@ -123,7 +124,7 @@ class ValidateCorrectAssetName(pyblish.api.InstancePlugin): if asset != context_asset: raise PublishXmlValidationError( self, msg, formatting_data={ - "node_name": instance[0]["name"].value(), + "node_name": node.name(), "wrong_name": asset, "correct_name": context_asset } diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index 7ce3ce0e3f..8ee8e631b8 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -1,6 +1,6 @@ import nuke import pyblish -from openpype.hosts.nuke.api.lib import maintained_selection +from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError @@ -25,14 +25,14 @@ class SelectCenterInNodeGraph(pyblish.api.Action): # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) - all_xC = list() - all_yC = list() + all_xC = [] + all_yC = [] # maintain selection - with maintained_selection(): + with napi.maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: - bdn = instance[0] + bdn = napi.get_instance_node(instance) xC = bdn.xpos() + bdn.screenWidth() / 2 yC = bdn.ypos() + bdn.screenHeight() / 2 diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 2321bd1fd4..05a4085483 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -1,6 +1,6 @@ import pyblish from openpype.pipeline import PublishXmlValidationError -from openpype.hosts.nuke.api import maintained_selection +from openpype.hosts.nuke import api as napi import nuke @@ -26,10 +26,10 @@ class OpenFailedGroupNode(pyblish.api.Action): instances = pyblish.api.instances_by_plugin(failed, plugin) # maintain selection - with maintained_selection(): + with napi.maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: - grpn = instance[0] + grpn = napi.get_instance_node(instance) nuke.showDag(grpn) @@ -45,7 +45,7 @@ class ValidateGizmo(pyblish.api.InstancePlugin): actions = [OpenFailedGroupNode] def process(self, instance): - grpn = instance[0] + grpn = napi.get_instance_node(instance) with grpn: connections_out = nuke.allNodes('Output') diff --git a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py index 1e59880f90..b7095e9ed7 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py +++ b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py @@ -1,6 +1,6 @@ import pyblish.api -from openpype.hosts.nuke.api import maintained_selection +from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError from openpype.pipeline.publish import RepairAction import nuke @@ -30,8 +30,13 @@ class ValidateOutputResolution(pyblish.api.InstancePlugin): @classmethod def get_reformat(cls, instance): + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + reformat = None - for inode in instance: + for inode in child_nodes: if inode.Class() != "Reformat": continue reformat = inode @@ -64,21 +69,26 @@ class ValidateOutputResolution(pyblish.api.InstancePlugin): @classmethod def repair(cls, instance): + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + invalid = cls.get_invalid(instance) - grp_node = instance[0] + grp_node = napi.get_instance_node(instance) if cls.missing_msg == invalid: # make sure we are inside of the group node with grp_node: # find input node and select it _input = None - for inode in instance: + for inode in child_nodes: if inode.Class() != "Input": continue _input = inode # add reformat node under it - with maintained_selection(): + with napi.maintained_selection(): _input['selected'].setValue(True) _rfn = nuke.createNode("Reformat", "name Reformat01") _rfn["resize"].setValue(0) diff --git a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py index 2bf1ff81f8..ffd5cee710 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py +++ b/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py @@ -5,7 +5,7 @@ import nuke import toml import pyblish.api from bson.objectid import ObjectId - +from openpype.hosts.nuke import api as napi from openpype.pipeline import ( discover_loader_plugins, load_container, @@ -31,22 +31,22 @@ class RepairReadLegacyAction(pyblish.api.Action): instances = pyblish.api.instances_by_plugin(failed, plugin) for instance in instances: - - data = toml.loads(instance[0]["avalon"].value()) - data["name"] = instance[0].name() - data["xpos"] = instance[0].xpos() - data["ypos"] = instance[0].ypos() + node = napi.get_instance_node(instance) + data = toml.loads(node["avalon"].value()) + data["name"] = node.name() + data["xpos"] = node.xpos() + data["ypos"] = node.ypos() data["extension"] = os.path.splitext( - instance[0]["file"].value() + node["file"].value() )[1][1:] data["connections"] = [] - for d in instance[0].dependent(): + for d in node.dependent(): for i in range(d.inputs()): - if d.input(i) == instance[0]: + if d.input(i) == node: data["connections"].append([i, d]) - nuke.delete(instance[0]) + nuke.delete(node) loader_name = "LoadSequence" if data["extension"] == "mov": @@ -72,7 +72,7 @@ class RepairReadLegacyAction(pyblish.api.Action): class ValidateReadLegacy(pyblish.api.InstancePlugin): - """Validate legacy read instance[0]s.""" + """Validate legacy read nodes.""" order = pyblish.api.ValidatorOrder optional = True diff --git a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py index 237ff423e5..c1e511f534 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py +++ b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py @@ -1,6 +1,7 @@ import os import pyblish.api import clique +from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError @@ -23,6 +24,7 @@ class RepairActionBase(pyblish.api.Action): def repair_knob(self, instances, state): for instance in instances: + node = napi.get_instance_node(instance) files_remove = [os.path.join(instance.data["outputDir"], f) for r in instance.data.get("representations", []) for f in r.get("files", []) @@ -31,7 +33,7 @@ class RepairActionBase(pyblish.api.Action): for f in files_remove: os.remove(f) self.log.debug("removing file: {}".format(f)) - instance[0]["render"].setValue(state) + node["render"].setValue(state) self.log.info("Rendering toggled to `{}`".format(state)) @@ -62,9 +64,10 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin): actions = [RepairCollectionActionToLocal, RepairCollectionActionToFarm] def process(self, instance): + node = napi.get_instance_node(instance) f_data = { - "node_name": instance[0]["name"].value() + "node_name": node.name() } for repre in instance.data["representations"]: diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py index 699526ef57..e9bcb08b00 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py @@ -7,7 +7,7 @@ import pyblish.api from openpype.pipeline import discover_creator_plugins from openpype.pipeline.publish import RepairAction from openpype.hosts.nuke.api.lib import get_avalon_knob_data - +from openpype.hosts.nuke import api as napi class ValidateWriteLegacy(pyblish.api.InstancePlugin): """Validate legacy write nodes.""" @@ -20,7 +20,7 @@ class ValidateWriteLegacy(pyblish.api.InstancePlugin): actions = [RepairAction] def process(self, instance): - node = instance[0] + node = napi.get_instance_node(instance) msg = "Clean up legacy write node \"{}\"".format(instance) if node.Class() not in ["Group", "Write"]: @@ -48,7 +48,7 @@ class ValidateWriteLegacy(pyblish.api.InstancePlugin): @classmethod def repair(cls, instance): - node = instance[0] + node = napi.get_instance_node(instance) if "Write" in node.Class(): data = toml.loads(node["avalon"].value()) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 26a563b13b..490ab2e5ae 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -5,6 +5,7 @@ from openpype.hosts.nuke.api.lib import ( set_node_knobs_from_settings, color_gui_to_int ) +from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError @@ -18,10 +19,15 @@ class RepairNukeWriteNodeAction(pyblish.api.Action): instances = get_errored_instances_from_context(context) for instance in instances: - write_group_node = instance[0] + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + + write_group_node = napi.get_instance_node(instance) # get write node from inside of group write_node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": write_node = x @@ -47,11 +53,16 @@ class ValidateNukeWriteNode(pyblish.api.InstancePlugin): hosts = ["nuke"] def process(self, instance): - write_group_node = instance[0] + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + + write_group_node = napi.get_instance_node(instance) # get write node from inside of group write_node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": write_node = x From f8cba8d477853ff024899084d9798f6c110d87af Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 15:39:35 +0200 Subject: [PATCH 048/211] nuke: renaming precollect to collect --- .../publish/{precollect_instances.py => collect_instances.py} | 4 ++-- .../publish/{precollect_workfile.py => collect_workfile.py} | 2 +- .../publish/{precollect_writes.py => collect_writes.py} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename openpype/hosts/nuke/plugins/publish/{precollect_instances.py => collect_instances.py} (98%) rename openpype/hosts/nuke/plugins/publish/{precollect_workfile.py => collect_workfile.py} (98%) rename openpype/hosts/nuke/plugins/publish/{precollect_writes.py => collect_writes.py} (99%) diff --git a/openpype/hosts/nuke/plugins/publish/precollect_instances.py b/openpype/hosts/nuke/plugins/publish/collect_instances.py similarity index 98% rename from openpype/hosts/nuke/plugins/publish/precollect_instances.py rename to openpype/hosts/nuke/plugins/publish/collect_instances.py index b396056eb9..54ad0229dd 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_instances.py +++ b/openpype/hosts/nuke/plugins/publish/collect_instances.py @@ -8,11 +8,11 @@ from openpype.hosts.nuke.api.lib import ( @pyblish.api.log -class PreCollectNukeInstances(pyblish.api.ContextPlugin): +class CollectNukeInstances(pyblish.api.ContextPlugin): """Collect all nodes with Avalon knob.""" order = pyblish.api.CollectorOrder - 0.49 - label = "Pre-collect Instances" + label = "Collect Instances" hosts = ["nuke", "nukeassist"] # presets diff --git a/openpype/hosts/nuke/plugins/publish/precollect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py similarity index 98% rename from openpype/hosts/nuke/plugins/publish/precollect_workfile.py rename to openpype/hosts/nuke/plugins/publish/collect_workfile.py index 822f405a6f..8b6ab5d072 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -15,7 +15,7 @@ class CollectWorkfile(pyblish.api.ContextPlugin): """Collect current script for publish.""" order = pyblish.api.CollectorOrder - 0.50 - label = "Pre-collect Workfile" + label = "Collect Workfile" hosts = ['nuke'] def process(self, context): # sourcery skip: avoid-builtin-shadow diff --git a/openpype/hosts/nuke/plugins/publish/precollect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py similarity index 99% rename from openpype/hosts/nuke/plugins/publish/precollect_writes.py rename to openpype/hosts/nuke/plugins/publish/collect_writes.py index 10eeb91644..8d7ae5d0df 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -19,7 +19,7 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): """Collect all write nodes.""" order = pyblish.api.CollectorOrder - 0.48 - label = "Pre-collect Writes" + label = "Collect Writes" hosts = ["nuke", "nukeassist"] families = ["write"] From 173a531f5f9d3b16c0779176093eb5b3488bef25 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:51:15 +0200 Subject: [PATCH 049/211] nuke: updating settings --- openpype/settings/defaults/project_anatomy/imageio.json | 2 +- openpype/settings/defaults/project_settings/nuke.json | 6 +++--- .../schemas/projects_schema/schema_project_nuke.json | 4 ++-- .../projects_schema/schemas/schema_nuke_publish.json | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/settings/defaults/project_anatomy/imageio.json b/openpype/settings/defaults/project_anatomy/imageio.json index f0be8f95f4..caa2a8a206 100644 --- a/openpype/settings/defaults/project_anatomy/imageio.json +++ b/openpype/settings/defaults/project_anatomy/imageio.json @@ -156,7 +156,7 @@ }, { "plugins": [ - "CreateWriteStill" + "CreateWriteImage" ], "nukeNodeClass": "Write", "knobs": [ diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 783b42348c..8e4dd163ab 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -99,10 +99,10 @@ ], "prenodes": {} }, - "CreateWriteStill": { + "CreateWriteImage": { "temp_rendering_path_template": "{work}/renders/nuke/{subset}/{subset}.{ext}", "default_variants": [ - "ImageFrame", + "StillFrame", "MPFrame", "LayoutFrame" ], @@ -125,7 +125,7 @@ } }, "publish": { - "PreCollectNukeInstances": { + "CollectInstanceData": { "sync_workfile_version_on_families": [ "nukenodes", "camera", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index 520985154e..00ba3d5f03 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -205,8 +205,8 @@ { "type": "dict", "collapsible": true, - "key": "CreateWriteStill", - "label": "CreateWriteStill", + "key": "CreateWriteImage", + "label": "CreateWriteImage", "is_group": true, "children": [ { 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 e5827a92c4..aa0c785e7a 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 @@ -11,8 +11,8 @@ { "type": "dict", "collapsible": true, - "key": "PreCollectNukeInstances", - "label": "PreCollectNukeInstances", + "key": "CollectInstanceData", + "label": "CollectInstanceData", "is_group": true, "children": [ { From 5ba40a60526fb1d221b6af6a323da3ebc8501eaa Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:52:16 +0200 Subject: [PATCH 050/211] Nuke: rename still to image and change family --- .../{create_write_still.py => create_write_image.py} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename openpype/hosts/nuke/plugins/create/{create_write_still.py => create_write_image.py} (96%) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_image.py similarity index 96% rename from openpype/hosts/nuke/plugins/create/create_write_still.py rename to openpype/hosts/nuke/plugins/create/create_write_image.py index b3a096a5ba..1bb114903f 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_image.py @@ -14,10 +14,10 @@ from openpype.lib import ( from openpype.hosts.nuke import api as napi -class CreateWriteStill(napi.NukeWriteCreator): - identifier = "create_write_still" - label = "Create Write Still Frame" - family = "still" +class CreateWriteImage(napi.NukeWriteCreator): + identifier = "create_write_image" + label = "Create Write Image" + family = "image" icon = "sign-out" def get_pre_create_attr_defs(self): From f8455915ac5dcb6f422c517b68438e5371ad4b4a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:52:52 +0200 Subject: [PATCH 051/211] Nuke: refactor instance collector --- .../plugins/publish/collect_instance_data.py | 45 +++++ .../nuke/plugins/publish/collect_instances.py | 158 ------------------ 2 files changed, 45 insertions(+), 158 deletions(-) create mode 100644 openpype/hosts/nuke/plugins/publish/collect_instance_data.py delete mode 100644 openpype/hosts/nuke/plugins/publish/collect_instances.py diff --git a/openpype/hosts/nuke/plugins/publish/collect_instance_data.py b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py new file mode 100644 index 0000000000..9614ebdea6 --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py @@ -0,0 +1,45 @@ +import nuke +import pyblish.api + + +@pyblish.api.log +class CollectInstanceData(pyblish.api.InstancePlugin): + """Collect all nodes with Avalon knob.""" + + order = pyblish.api.CollectorOrder - 0.49 + label = "Collect Instance Data" + hosts = ["nuke", "nukeassist"] + + # presets + sync_workfile_version_on_families = [] + + def process(self, instance): + family = instance.data["family"] + + # Get format + root = nuke.root() + format_ = root['format'].value() + resolution_width = format_.width() + resolution_height = format_.height() + pixel_aspect = format_.pixelAspect() + + # sync workfile version + if family in self.sync_workfile_version_on_families: + self.log.debug( + "Syncing version with workfile for '{}'".format( + family + ) + ) + # get version to instance for integration + instance.data['version'] = instance.context.data['version'] + + instance.data.update({ + "step": 1, + "fps": root['fps'].value(), + "resolutionWidth": resolution_width, + "resolutionHeight": resolution_height, + "pixelAspect": pixel_aspect + + }) + self.log.debug("Collected instance: {}".format( + instance.data)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_instances.py b/openpype/hosts/nuke/plugins/publish/collect_instances.py deleted file mode 100644 index 54ad0229dd..0000000000 --- a/openpype/hosts/nuke/plugins/publish/collect_instances.py +++ /dev/null @@ -1,158 +0,0 @@ -import nuke -import pyblish.api - -from openpype.hosts.nuke.api.lib import ( - add_publish_knob, - get_avalon_knob_data -) - - -@pyblish.api.log -class CollectNukeInstances(pyblish.api.ContextPlugin): - """Collect all nodes with Avalon knob.""" - - order = pyblish.api.CollectorOrder - 0.49 - label = "Collect Instances" - hosts = ["nuke", "nukeassist"] - - # presets - sync_workfile_version_on_families = [] - - def process(self, context): - instances = [] - - root = nuke.root() - - self.log.debug("nuke.allNodes(): {}".format(nuke.allNodes())) - for node in nuke.allNodes(): - - if node.Class() in ["Viewer", "Dot"]: - continue - - try: - if node["disable"].value(): - continue - except Exception as E: - self.log.warning(E) - - # get data from avalon knob - avalon_knob_data = get_avalon_knob_data( - node, ["avalon:", "ak:"]) - - self.log.debug("avalon_knob_data: {}".format(avalon_knob_data)) - - if not avalon_knob_data: - continue - - if avalon_knob_data["id"] != "pyblish.avalon.instance": - continue - - # establish families - family = avalon_knob_data["family"] - families_ak = avalon_knob_data.get("families", []) - families = [] - - # except disabled nodes but exclude backdrops in test - if ("nukenodes" not in family) and (node["disable"].value()): - continue - - subset = avalon_knob_data.get( - "subset", None) or node["name"].value() - - # Create instance - instance = context.create_instance(subset) - instance.append(node) - - suspend_publish = False - if "suspend_publish" in node.knobs(): - suspend_publish = node["suspend_publish"].value() - instance.data["suspend_publish"] = suspend_publish - - # get review knob value - review = False - if "review" in node.knobs(): - review = node["review"].value() - - if review: - families.append("review") - - # Add all nodes in group instances. - if node.Class() == "Group": - # only alter families for render family - if families_ak and "write" in families_ak.lower(): - target = node["render"].value() - if target == "Use existing frames": - # Local rendering - self.log.info("flagged for no render") - families.append(families_ak.lower()) - elif target == "Local": - # Local rendering - self.log.info("flagged for local render") - families.append("{}.local".format(family)) - family = families_ak.lower() - elif target == "On farm": - # Farm rendering - self.log.info("flagged for farm render") - instance.data["transfer"] = False - instance.data["farm"] = True - families.append("{}.farm".format(family)) - family = families_ak.lower() - - node.begin() - for i in nuke.allNodes(): - instance.append(i) - node.end() - - if not families and families_ak and family not in [ - "render", "prerender"]: - families.append(families_ak.lower()) - - self.log.debug("__ family: `{}`".format(family)) - self.log.debug("__ families: `{}`".format(families)) - - # Get format - format_ = root['format'].value() - resolution_width = format_.width() - resolution_height = format_.height() - pixel_aspect = format_.pixelAspect() - - # get publish knob value - if "publish" not in node.knobs(): - add_publish_knob(node) - - # sync workfile version - _families_test = [family] + families - self.log.debug("__ _families_test: `{}`".format(_families_test)) - for family_test in _families_test: - if family_test in self.sync_workfile_version_on_families: - self.log.debug( - "Syncing version with workfile for '{}'".format( - family_test - ) - ) - # get version to instance for integration - instance.data['version'] = instance.context.data['version'] - - instance.data.update({ - "subset": subset, - "asset": avalon_knob_data["asset"], - "label": node.name(), - "name": node.name(), - "subset": subset, - "family": family, - "families": families, - "avalonKnob": avalon_knob_data, - "step": 1, - "publish": node.knob('publish').value(), - "fps": nuke.root()['fps'].value(), - "resolutionWidth": resolution_width, - "resolutionHeight": resolution_height, - "pixelAspect": pixel_aspect, - "review": review, - "representations": [] - - }) - self.log.info("collected instance: {}".format(instance.data)) - instances.append(instance) - - self.log.debug("context: {}".format(context)) From 0e3a8ffb82008b895813caf8ac60b19f8b5c5cd9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:53:12 +0200 Subject: [PATCH 052/211] nuke: refactor collect writes --- .../nuke/plugins/publish/collect_writes.py | 224 ++++++++---------- 1 file changed, 102 insertions(+), 122 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py index 8d7ae5d0df..32d837f400 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -1,17 +1,8 @@ import os -import re from pprint import pformat import nuke import pyblish.api - -from openpype.client import ( - get_last_version_by_subset_name, - get_representations, -) -from openpype.pipeline import ( - legacy_io, - get_representation_path, -) +from openpype.hosts.nuke import api as napi @pyblish.api.log @@ -21,35 +12,49 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): order = pyblish.api.CollectorOrder - 0.48 label = "Collect Writes" hosts = ["nuke", "nukeassist"] - families = ["write"] + families = ["render", "prerender", "image"] def process(self, instance): - _families_test = [instance.data["family"]] + instance.data["families"] - self.log.debug("_families_test: {}".format(_families_test)) + self.log.debug(pformat(instance.data)) + instance.data.update(instance.data["creator_attributes"]) - child_nodes = ( - instance.data.get("transientData", {}).get("childNodes") - or instance + group_node = napi.get_instance_node(instance) + render_target = instance.data["render_target"] + family = instance.data["family"] + families = instance.data["families"] + + # add targeted family to families + instance.data["families"].append( + "{}.{}".format(family, render_target) ) + # add additional keys to farm targeted + if render_target == "farm": + # Farm rendering + self.log.info("flagged for farm render") + instance.data["transfer"] = False + instance.data["farm"] = True - node = None + child_nodes = napi.get_instance_group_node_childs(instance) + instance.data["transientData"]["childNodes"] = child_nodes + + write_node = None for x in child_nodes: if x.Class() == "Write": - node = x + write_node = x - if node is None: + if write_node is None: + self.log.warning( + "Created node '{}' is missing write node!".format( + group_node.name() + ) + ) return - instance.data["writeNode"] = node + instance.data["writeNode"] = write_node self.log.debug("checking instance: {}".format(instance)) # Determine defined file type - ext = node["file_type"].value() - - # Determine output type - output_type = "img" - if ext == "mov": - output_type = "mov" + ext = write_node["file_type"].value() # Get frame range handle_start = instance.context.data["handleStart"] @@ -58,105 +63,85 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): last_frame = int(nuke.root()["last_frame"].getValue()) frame_length = int(last_frame - first_frame + 1) - if node["use_limit"].getValue(): - first_frame = int(node["first"].getValue()) - last_frame = int(node["last"].getValue()) + if write_node["use_limit"].getValue(): + first_frame = int(write_node["first"].getValue()) + last_frame = int(write_node["last"].getValue()) - # Prepare expected output paths by evaluating each frame of write node - # - paths are first collected to set to avoid duplicated paths, then - # sorted and converted to list - node_file = node["file"] - expected_paths = list(sorted({ - node_file.evaluate(frame) - for frame in range(first_frame, last_frame + 1) - })) - expected_filenames = [ - os.path.basename(filepath) - for filepath in expected_paths - ] - path = nuke.filename(node) - output_dir = os.path.dirname(path) + write_file_path = nuke.filename(write_node) + output_dir = os.path.dirname(write_file_path) self.log.debug('output dir: {}'.format(output_dir)) - # create label - name = node.name() - # Include start and end render frame in label - label = "{0} ({1}-{2})".format( - name, - int(first_frame), - int(last_frame) - ) - - if [fm for fm in _families_test - if fm in ["render", "prerender", "still"]]: - if "representations" not in instance.data: - instance.data["representations"] = list() + if render_target == "frame": representation = { 'name': ext, 'ext': ext, "stagingDir": output_dir, - "tags": list() + "tags": [] } - try: - collected_frames = [ - filename - for filename in os.listdir(output_dir) - if filename in expected_filenames - ] - if collected_frames: - collected_frames_len = len(collected_frames) - frame_start_str = "%0{}d".format( - len(str(last_frame))) % first_frame - representation['frameStart'] = frame_start_str + # get file path knob + node_file_knob = write_node["file"] + # list file paths based on input frames + expected_paths = list(sorted({ + node_file_knob.evaluate(frame) + for frame in range(first_frame, last_frame + 1) + })) - # in case slate is expected and not yet rendered - self.log.debug("_ frame_length: {}".format(frame_length)) - self.log.debug( - "_ collected_frames_len: {}".format( - collected_frames_len)) - # this will only run if slate frame is not already - # rendered from previews publishes - if "slate" in _families_test \ - and (frame_length == collected_frames_len) \ - and ("prerender" not in _families_test): - frame_slate_str = "%0{}d".format( - len(str(last_frame))) % (first_frame - 1) - slate_frame = collected_frames[0].replace( - frame_start_str, frame_slate_str) - collected_frames.insert(0, slate_frame) + # convert only to base names + expected_filenames = [ + os.path.basename(filepath) + for filepath in expected_paths + ] + + # make sure files are existing at folder + collected_frames = [ + filename + for filename in os.listdir(output_dir) + if filename in expected_filenames + ] + + if collected_frames: + collected_frames_len = len(collected_frames) + frame_start_str = "%0{}d".format( + len(str(last_frame))) % first_frame + representation['frameStart'] = frame_start_str + + # in case slate is expected and not yet rendered + self.log.debug("_ frame_length: {}".format(frame_length)) + self.log.debug("_ collected_frames_len: {}".format( + collected_frames_len)) + + # this will only run if slate frame is not already + # rendered from previews publishes + if ( + "slate" in families + and frame_length == collected_frames_len + and family == "render" + ): + frame_slate_str = ( + "{{:0{}d}}".format(len(str(last_frame))) + ).format(first_frame - 1) + + slate_frame = collected_frames[0].replace( + frame_start_str, frame_slate_str) + collected_frames.insert(0, slate_frame) if collected_frames_len == 1: representation['files'] = collected_frames.pop() - if "still" in _families_test: - instance.data['family'] = 'image' - instance.data["families"].remove('still') else: representation['files'] = collected_frames - instance.data["representations"].append(representation) - except Exception: - instance.data["representations"].append(representation) - self.log.debug("couldn't collect frames: {}".format(label)) - # Add version data to instance - colorspace = node["colorspace"].value() - - # remove default part of the string - if "default (" in colorspace: - colorspace = re.sub(r"default.\(|\)", "", colorspace) - self.log.debug("colorspace: `{}`".format(colorspace)) + instance.data["representations"].append(representation) + # get colorspace and add to version data + colorspace = napi.get_colorspace_from_node(write_node) version_data = { - "families": [ - _f.replace(".local", "").replace(".farm", "") - for _f in _families_test if "write" != _f - ], "colorspace": colorspace } - group_node = [x for x in instance if x.Class() == "Group"][0] + # get deadline related attributes dl_chunk_size = 1 if "deadlineChunkSize" in group_node.knobs(): dl_chunk_size = group_node["deadlineChunkSize"].value() @@ -171,27 +156,16 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): instance.data.update({ "versionData": version_data, - "path": path, + "path": write_file_path, "outputDir": output_dir, "ext": ext, - "label": label, - "outputType": output_type, "colorspace": colorspace, "deadlineChunkSize": dl_chunk_size, "deadlinePriority": dl_priority, "deadlineConcurrentTasks": dl_concurrent_tasks }) - if self.is_prerender(_families_test): - instance.data.update({ - "handleStart": 0, - "handleEnd": 0, - "frameStart": first_frame, - "frameEnd": last_frame, - "frameStartHandle": first_frame, - "frameEndHandle": last_frame, - }) - else: + if family == "render": instance.data.update({ "handleStart": handle_start, "handleEnd": handle_end, @@ -200,13 +174,19 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): "frameStartHandle": first_frame, "frameEndHandle": last_frame, }) + else: + instance.data.update({ + "handleStart": 0, + "handleEnd": 0, + "frameStart": first_frame, + "frameEnd": last_frame, + "frameStartHandle": first_frame, + "frameEndHandle": last_frame, + }) - # make sure rendered sequence on farm will - # be used for exctract review - if not instance.data["review"]: - instance.data["useSequenceForReview"] = False + # make sure rendered sequence on farm will + # be used for exctract review + if not instance.data["review"]: + instance.data["useSequenceForReview"] = False self.log.debug("instance.data: {}".format(pformat(instance.data))) - - def is_prerender(self, families): - return next((f for f in families if "prerender" in f), None) From ef27fc4cf21ffd99c0ffdd949f8d045caa86de88 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:53:34 +0200 Subject: [PATCH 053/211] Nuke: refactor collect slates --- openpype/hosts/nuke/plugins/publish/collect_slate_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index 0a98bcf973..e3f24a233e 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -9,7 +9,7 @@ class CollectSlate(pyblish.api.InstancePlugin): order = pyblish.api.CollectorOrder + 0.09 label = "Collect Slate Node" hosts = ["nuke"] - families = ["render", "render.local", "render.farm"] + families = ["render"] def process(self, instance): node = napi.get_instance_node(instance) From ce0d2b8fe16a03be90a917cc666f4dcc5158fb70 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:54:14 +0200 Subject: [PATCH 054/211] nuke: adding supporting functions to plugin.py --- openpype/hosts/nuke/api/__init__.py | 6 ++++- openpype/hosts/nuke/api/plugin.py | 37 ++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 156b3f0de0..8aaaff43b3 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -14,7 +14,9 @@ from .plugin import ( NukeWriteCreator, NukeCreatorError, OpenPypeCreator, - get_instance_node + get_instance_node, + get_instance_group_node_childs, + get_colorspace_from_node ) from .pipeline import ( NukeHost, @@ -66,6 +68,8 @@ __all__ = ( "OpenPypeCreator", "NukeHost", "get_instance_node", + "get_instance_group_node_childs", + "get_colorspace_from_node", "ls", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 193c2e8c2d..45f16b2943 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,5 +1,5 @@ import nuke - +import re import os import sys import six @@ -415,6 +415,41 @@ def get_instance_node(instance): return instance[0] +def get_instance_group_node_childs(instance): + """Return list of instance group node children + + Args: + instance (pyblish.Instance): pyblish instance + + Returns: + list: [nuke.Node] + """ + node = get_instance_node(instance) + + if node.Class() != "Group": + return + + # collect child nodes + child_nodes = [] + # iterate all nodes + for node in nuke.allNodes(group=node): + # add contained nodes to instance's node list + child_nodes.append(node) + + return child_nodes + + +def get_colorspace_from_node(node): + # Add version data to instance + colorspace = node["colorspace"].value() + + # remove default part of the string + if "default (" in colorspace: + colorspace = re.sub(r"default.\(|\)", "", colorspace) + + return colorspace + + def get_review_presets_config(): settings = get_current_project_settings() review_profiles = ( From 0bce4fc67ad3a93b2014a94834f3c293c51bf9f9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:55:38 +0200 Subject: [PATCH 055/211] nuke: adding deprecated decorator --- openpype/hosts/nuke/api/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 4478633198..df0b303878 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -691,6 +691,7 @@ def get_nuke_imageio_settings(): return get_anatomy_settings(Context.project_name)["imageio"]["nuke"] +@deprecated("openpype.hosts.nuke.api.lib.get_nuke_imageio_settings") def get_created_node_imageio_setting_legacy(nodeclass, creator, subset): '''[DEPRICATED] Get preset data for dataflow (fileType, compression, bitDepth) ''' From a45666c4c45325bd13973397824d2ce5fc698a3a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Oct 2022 17:37:32 +0200 Subject: [PATCH 056/211] Nuke: plugin better update instances --- openpype/hosts/nuke/api/plugin.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 45f16b2943..748c52eb1f 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -198,15 +198,11 @@ class NukeCreator(NewCreator): def update_instances(self, update_list): for created_inst, _changes in update_list: instance_node = created_inst.transient_data["node"] - current_data = created_inst.data set_node_data( instance_node, INSTANCE_DATA_KNOB, - { - key: value[1] for key, value in _changes.items() - if current_data.get(key) != value[0] - } + created_inst.data_to_store() ) def remove_instances(self, instances): From c975429799163f7f2fbbeb52c6654c1f604eb000 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Oct 2022 17:38:04 +0200 Subject: [PATCH 057/211] Nuke: update write validator --- .../nuke/plugins/publish/validate_write_nodes.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 490ab2e5ae..ab1671ad0e 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -6,7 +6,10 @@ from openpype.hosts.nuke.api.lib import ( color_gui_to_int ) from openpype.hosts.nuke import api as napi -from openpype.pipeline import PublishXmlValidationError +from openpype.pipeline.publish import ( + PublishXmlValidationError, + OptionalPyblishPluginMixin, +) @pyblish.api.log @@ -38,7 +41,10 @@ class RepairNukeWriteNodeAction(pyblish.api.Action): self.log.info("Node attributes were fixed") -class ValidateNukeWriteNode(pyblish.api.InstancePlugin): +class ValidateNukeWriteNode( + OptionalPyblishPluginMixin, + pyblish.api.InstancePlugin +): """ Validate Write node's knobs. Compare knobs on write node inside the render group @@ -48,11 +54,14 @@ class ValidateNukeWriteNode(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder optional = True families = ["render"] - label = "Write Node" + label = "Validate write node" actions = [RepairNukeWriteNodeAction] hosts = ["nuke"] def process(self, instance): + if not self.is_active(instance.data): + return + child_nodes = ( instance.data.get("transientData", {}).get("childNodes") or instance From 0271e3b60fe018bf78f9fad25fe2c81afab26a33 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Oct 2022 20:58:10 +0200 Subject: [PATCH 058/211] Nuke: improving error message. --- openpype/hosts/nuke/plugins/create/create_backdrop.py | 4 ++-- openpype/hosts/nuke/plugins/create/create_camera.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index 40eaab08cf..d82456392a 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -45,8 +45,8 @@ class CreateBackdrop(NukeCreator): def create(self, subset_name, instance_data, pre_create_data): if self.check_existing_subset(subset_name, instance_data): raise NukeCreatorError( - ("subset {} is already published with different HDA" - "definition.").format(subset_name)) + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) instance = super(CreateBackdrop, self).create( subset_name, diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index 0b538d0088..ea2fd4b971 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -42,8 +42,8 @@ class CreateCamera(NukeCreator): def create(self, subset_name, instance_data, pre_create_data): if self.check_existing_subset(subset_name, instance_data): raise NukeCreatorError( - ("subset {} is already published with different HDA" - "definition.").format(subset_name)) + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) instance = super(CreateCamera, self).create( subset_name, From 0a29bcfcc5f1724080993dfad76c47c1965b9f01 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Oct 2022 20:58:26 +0200 Subject: [PATCH 059/211] Nuke: refactory model creator --- .../hosts/nuke/plugins/create/create_model.py | 130 ++++++++---------- 1 file changed, 55 insertions(+), 75 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index 15a4e3ab8a..bfddcb64c3 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -1,87 +1,67 @@ import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateModel(plugin.OpenPypeCreator): - """Add Publishable Model Geometry""" +class CreateModel(NukeCreator): + """Add Publishable Camera""" - name = "model" + identifier = "create_model" label = "Create 3d Model" family = "model" icon = "cube" - defaults = ["Main"] + default_variants = ["Main"] - def __init__(self, *args, **kwargs): - super(CreateModel, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xff3200ff" - return + # plugin attributes + node_color = "0xff3200ff" - def process(self): - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes - for n in nodes: - n['selected'].setValue(0) - end_nodes = list() - - # get the latest nodes in tree for selecion - for n in nodes: - x = n - end = 0 - while end == 0: - try: - x = x.dependent()[0] - except: - end_node = x - end = 1 - end_nodes.append(end_node) - - # set end_nodes - end_nodes = list(set(end_nodes)) - - # check if nodes is 3d nodes - for n in end_nodes: - n['selected'].setValue(1) - sn = nuke.createNode("Scene") - if not sn.input(0): - end_nodes.remove(n) - nuke.delete(sn) - - # loop over end nodes - for n in end_nodes: - n['selected'].setValue(1) - - self.nodes = nuke.selectedNodes() - nodes = self.nodes - if len(nodes) >= 1: - # loop selected nodes - for n in nodes: - data = self.data.copy() - if len(nodes) > 1: - # rename subset name only if more - # then one node are selected - subset = self.family + n["name"].value().capitalize() - data["subset"] = subset - - # change node color - n["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - set_avalon_knob_data(n, data) - return True + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + created_node = self.selected_nodes[0] else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return + created_node = nuke.createNode("Scene") + + created_node["tile_color"].setValue( + int(self.node_color, 16)) + + created_node["name"].setValue(node_name) + + self.add_info_knob(created_node) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) + + instance = super(CreateModel, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(self.selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one camera node") else: - # if selected is off then create one node - model_node = nuke.createNode("WriteGeo") - model_node["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - instance = set_avalon_knob_data(model_node, self.data) - return instance + self.selected_nodes = [] + + self.log.debug("Selection is: {}".format(self.selected_nodes)) From 3361c9a66d4921741ec836a5728a24c6ea6cb5f3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 11 Oct 2022 17:30:53 +0200 Subject: [PATCH 060/211] nuke: convert_to_valid_instaces function convert old instances to new publisher --- openpype/hosts/nuke/api/plugin.py | 139 +++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 748c52eb1f..8ef6c60296 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,3 +1,4 @@ +from pprint import pformat import nuke import re import os @@ -37,6 +38,7 @@ from .lib import ( set_node_knobs_from_settings, get_view_process_node, set_node_data, + get_node_data, deprecated ) from .pipeline import ( @@ -189,6 +191,10 @@ class NukeCreator(NewCreator): def collect_instances(self): for (node, data) in list_instances(creator_id=self.identifier): + self.log.debug("_" * 50) + self.log.debug("_ self.identifier: `{}`".format(self.identifier)) + self.log.debug("_ data: `{}`".format(pformat(data))) + created_instance = CreatedInstance.from_existing( data, self ) @@ -337,8 +343,7 @@ class NukeWriteCreator(NukeCreator): def apply_settings( self, project_settings, - system_settings, - # anatomy_settings + system_settings ): """Method called on initialization of plugin to apply settings.""" @@ -1080,3 +1085,133 @@ class AbstractWriteRender(OpenPypeCreator): node (nuke.Node): group node with data as Knobs """ pass + + +def convert_to_valid_instaces(): + """ Check and convert to latest publisher instances + + Also save as new minor version of workfile. + """ + def family_to_identifier(family): + mapping = { + "render": "create_write_render", + "prerender": "create_write_prerender", + "still": "create_write_image", + "model": "create_model", + "camera": "create_camera", + "nukenodes": "create_backdrop", + "gizmo": "create_gizmo", + "source": "create_source" + + } + return mapping[family] + + from openpype.hosts.nuke.api.lib import ( + get_avalon_knob_data + ) + from openpype.hosts.nuke.api import workio + + task_name = legacy_io.Session["AVALON_TASK"] + + # save into new workfile + current_file = workio.current_file() + new_workfile = current_file[:-3] + "_publisherConvert" + current_file[-3:] + + path = new_workfile.replace("\\", "/") + nuke.scriptSaveAs(new_workfile, overwrite=1) + nuke.Root()["name"].setValue(path) + nuke.Root()["project_directory"].setValue(os.path.dirname(path)) + nuke.Root().setModified(False) + + # loop all nodes and convert + for node in nuke.allNodes(recurseGroups=True): + transfer_data = { + "creator_attributes": {} + } + creator_attr = transfer_data["creator_attributes"] + + if node.Class() in ["Viewer", "Dot"]: + continue + + if get_node_data(node, INSTANCE_DATA_KNOB): + continue + + # get data from avalon knob + avalon_knob_data = get_avalon_knob_data( + node, ["avalon:", "ak:"]) + + if not avalon_knob_data: + continue + + if avalon_knob_data["id"] != "pyblish.avalon.instance": + continue + + transfer_data.update({ + k: v for k, v in avalon_knob_data.items() + if k not in ["families", "creator"] + }) + + transfer_data["task"] = task_name + + family = avalon_knob_data["family"] + # establish families + families_ak = avalon_knob_data.get("families", []) + + if "suspend_publish" in node.knobs(): + creator_attr["suspended_publish"] = ( + node["suspend_publish"].value()) + + # get review knob value + if "review" in node.knobs(): + creator_attr["review"] = ( + node["review"].value()) + + if "publish" in node.knobs(): + transfer_data["active"] = ( + node["publish"].value()) + + # add idetifier + transfer_data["creator_identifier"] = family_to_identifier(family) + + # Add all nodes in group instances. + if node.Class() == "Group": + # only alter families for render family + if families_ak and "write" in families_ak.lower(): + target = node["render"].value() + if target == "Use existing frames": + creator_attr["render_target"] = "frames" + elif target == "Local": + # Local rendering + creator_attr["render_target"] = "local" + elif target == "On farm": + # Farm rendering + creator_attr["render_target"] = "farm" + + if "deadlinePriority" in node.knobs(): + transfer_data["farm_priority"] = ( + node["deadlinePriority"].value()) + if "deadlineChunkSize" in node.knobs(): + creator_attr["farm_chunk"] = ( + node["deadlineChunkSize"].value()) + if "deadlineConcurrentTasks" in node.knobs(): + creator_attr["farm_concurency"] = ( + node["deadlineConcurrentTasks"].value()) + + remove_knobs = [ + "review", "publish", "render", "suspend_publish", "warn", "divd", + "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", + "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" + ] + + # remove all old knobs + for knob in node.allKnobs(): + if knob.name() in remove_knobs: + node.removeKnob(knob) + elif "avalon" in knob.name(): + node.removeKnob(knob) + + # add new instance knob with transfer data + set_node_data( + node, INSTANCE_DATA_KNOB, transfer_data) + + nuke.scriptSave() From e185ba57cd2b9adf8d1ffa182ccc57149c570b1d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 15:43:30 +0200 Subject: [PATCH 061/211] nuke: fixing missing instance data --- openpype/hosts/nuke/plugins/create/workfile_creator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index ae54d6bcb2..ae05cee99f 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -42,7 +42,7 @@ class WorkfileCreator(AutoCreator): }) instance_data.update(self.get_dynamic_data( self.default_variant, task_name, asset_doc, - project_name, host_name + project_name, host_name, instance_data )) instance = CreatedInstance( From 8180a02b1873170dd7bf02364496dd69082a5d95 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 15:44:47 +0200 Subject: [PATCH 062/211] nuke: better creator names --- openpype/hosts/nuke/plugins/create/create_backdrop.py | 2 +- openpype/hosts/nuke/plugins/create/create_camera.py | 2 +- openpype/hosts/nuke/plugins/create/create_model.py | 2 +- openpype/hosts/nuke/plugins/create/create_read.py | 2 +- openpype/hosts/nuke/plugins/create/create_write_image.py | 2 +- openpype/hosts/nuke/plugins/create/create_write_prerender.py | 2 +- openpype/hosts/nuke/plugins/create/create_write_render.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index d82456392a..ebc66e95a7 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -13,7 +13,7 @@ class CreateBackdrop(NukeCreator): """Add Publishable Backdrop""" identifier = "create_backdrop" - label = "Create Backdrop" + label = "Nukenodes (backdrop)" family = "nukenodes" icon = "file-archive-o" maintain_selection = True diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index ea2fd4b971..2a48b8a72b 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -10,7 +10,7 @@ class CreateCamera(NukeCreator): """Add Publishable Camera""" identifier = "create_camera" - label = "Create 3d Camera" + label = "Camera (3d)" family = "camera" icon = "camera" diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index bfddcb64c3..a1a96bf412 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -10,7 +10,7 @@ class CreateModel(NukeCreator): """Add Publishable Camera""" identifier = "create_model" - label = "Create 3d Model" + label = "Model (3d)" family = "model" icon = "cube" default_variants = ["Main"] diff --git a/openpype/hosts/nuke/plugins/create/create_read.py b/openpype/hosts/nuke/plugins/create/create_read.py index 87a9dff0f8..d4f63e6b9f 100644 --- a/openpype/hosts/nuke/plugins/create/create_read.py +++ b/openpype/hosts/nuke/plugins/create/create_read.py @@ -11,7 +11,7 @@ from openpype.hosts.nuke.api.lib import ( class CrateRead(plugin.OpenPypeCreator): # change this to template preset name = "ReadCopy" - label = "Create Read Copy" + label = "Source (read)" hosts = ["nuke"] family = "source" families = family diff --git a/openpype/hosts/nuke/plugins/create/create_write_image.py b/openpype/hosts/nuke/plugins/create/create_write_image.py index 1bb114903f..e9ff33a32b 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_image.py +++ b/openpype/hosts/nuke/plugins/create/create_write_image.py @@ -16,7 +16,7 @@ from openpype.hosts.nuke import api as napi class CreateWriteImage(napi.NukeWriteCreator): identifier = "create_write_image" - label = "Create Write Image" + label = "Image (write)" family = "image" icon = "sign-out" diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index 1ce30379ad..b7d0f4ade9 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -16,7 +16,7 @@ from openpype.hosts.nuke import api as napi class CreateWritePrerender(napi.NukeWriteCreator): identifier = "create_write_prerender" - label = "Create Write Prerender" + label = "Prerender (write)" family = "prerender" icon = "sign-out" diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 89696f55e0..3d96e8c13b 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -16,7 +16,7 @@ from openpype.hosts.nuke import api as napi class CreateWriteRender(napi.NukeWriteCreator): identifier = "create_write_render" - label = "Create Write Render" + label = "Render (write)" family = "render" icon = "sign-out" From 8521a2eac42a6f3c081e08e3351383b197de07c1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 15:45:38 +0200 Subject: [PATCH 063/211] nuke: missing try to catch ValueError --- openpype/hosts/nuke/api/pipeline.py | 8 ++++++-- openpype/hosts/nuke/api/plugin.py | 13 ++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index c93a4f090f..258b09f7a8 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -37,7 +37,6 @@ from .lib import ( check_inventory_versions, set_avalon_knob_data, read_avalon_data, - get_avalon_knob_data, on_script_load, dirmap_file_name_filter, add_scripts_menu, @@ -61,6 +60,7 @@ from .workio import ( work_root, current_file ) +from openpype.hosts.nuke.api import plugin log = Logger.get_logger(__name__) @@ -297,7 +297,11 @@ def _install_menu(): "Experimental tools...", lambda: host_tools.show_experimental_tools_dialog(parent=main_window) ) - + menu.addSeparator() + menu.addCommand( + "Convert old publishing instances", + plugin.convert_to_valid_instaces + ) # add reload pipeline only in debug mode if bool(os.getenv("NUKE_DEBUG")): menu.addSeparator() diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index c9460295fb..96d9b48ba6 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1202,14 +1202,17 @@ def convert_to_valid_instaces(): "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" ] + print(node.name()) # remove all old knobs for knob in node.allKnobs(): - if knob.name() in remove_knobs: - node.removeKnob(knob) - elif "avalon" in knob.name(): - node.removeKnob(knob) - + try: + if knob.name() in remove_knobs: + node.removeKnob(knob) + elif "avalon" in knob.name(): + node.removeKnob(knob) + except ValueError: + pass # add new instance knob with transfer data set_node_data( node, INSTANCE_DATA_KNOB, transfer_data) From 8965b5712bbe2a3639493f970374f5662a229697 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 16:24:52 +0200 Subject: [PATCH 064/211] nuke: removing unused code --- openpype/hosts/nuke/plugins/create/create_camera.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index 2a48b8a72b..c559aa2756 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -64,12 +64,3 @@ class CreateCamera(NukeCreator): self.selected_nodes = [] self.log.debug("Selection is: {}".format(self.selected_nodes)) - - def apply_settings(self, project_settings, system_settings): - """Method called on initialization of plugin to apply settings.""" - - # only selected keys ideally - # settings = self.get_creator_settings(project_settings) - - # self.key = settings["key"] - pass \ No newline at end of file From 1407de25a5651909446070aa999aa869adfef82b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 16:25:11 +0200 Subject: [PATCH 065/211] nuke: refactor create read to create source --- .../hosts/nuke/plugins/create/create_read.py | 57 ------------ .../nuke/plugins/create/create_source.py | 93 +++++++++++++++++++ 2 files changed, 93 insertions(+), 57 deletions(-) delete mode 100644 openpype/hosts/nuke/plugins/create/create_read.py create mode 100644 openpype/hosts/nuke/plugins/create/create_source.py diff --git a/openpype/hosts/nuke/plugins/create/create_read.py b/openpype/hosts/nuke/plugins/create/create_read.py deleted file mode 100644 index d4f63e6b9f..0000000000 --- a/openpype/hosts/nuke/plugins/create/create_read.py +++ /dev/null @@ -1,57 +0,0 @@ -from collections import OrderedDict - -import nuke - -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data -) - - -class CrateRead(plugin.OpenPypeCreator): - # change this to template preset - name = "ReadCopy" - label = "Source (read)" - hosts = ["nuke"] - family = "source" - families = family - icon = "film" - defaults = ["Effect", "Backplate", "Fire", "Smoke"] - - def __init__(self, *args, **kwargs): - super(CrateRead, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - data = OrderedDict() - data['family'] = self.family - data['families'] = self.families - - for k, v in self.data.items(): - if k not in data.keys(): - data.update({k: v}) - - self.data = data - - def process(self): - self.name = self.data["subset"] - nodes = self.nodes - - if not nodes or len(nodes) == 0: - msg = "Please select Read node" - self.log.error(msg) - nuke.message(msg) - else: - count_reads = 0 - for node in nodes: - if node.Class() != 'Read': - continue - avalon_data = self.data - avalon_data['subset'] = "{}".format(self.name) - set_avalon_knob_data(node, avalon_data) - node['tile_color'].setValue(16744935) - count_reads += 1 - - if count_reads < 1: - msg = "Please select Read node" - self.log.error(msg) - nuke.message(msg) - return diff --git a/openpype/hosts/nuke/plugins/create/create_source.py b/openpype/hosts/nuke/plugins/create/create_source.py new file mode 100644 index 0000000000..48f9f86219 --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/create_source.py @@ -0,0 +1,93 @@ +import nuke +import six +import sys +from openpype.hosts.nuke.api import ( + INSTANCE_DATA_KNOB, + NukeCreator, + NukeCreatorError, + set_node_data +) +from openpype.pipeline import ( + CreatedInstance +) + + +class CreateSource(NukeCreator): + """Add Publishable Read with source""" + + identifier = "create_source" + label = "Source (read)" + family = "source" + icon = "film" + default_variants = ["Effect", "Backplate", "Fire", "Smoke"] + + # plugin attributes + node_color = "0xff9100ff" + + def create_instance_node( + self, + node_name, + read_node + ): + read_node["tile_color"].setValue( + int(self.node_color, 16)) + read_node["name"].setValue(node_name) + self.add_info_knob(read_node) + return read_node + + def create(self, subset_name, instance_data, pre_create_data): + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + try: + for read_node in self.selected_nodes: + if read_node.Class() != 'Read': + continue + + node_name = read_node.name() + _subset_name = subset_name + node_name + + # make sure subset name is unique + if self.check_existing_subset(_subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published" + "definition.").format(_subset_name)) + + instance_node = self.create_instance_node( + _subset_name, + read_node + ) + instance = CreatedInstance( + self.family, + _subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2]) + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + else: + NukeCreatorError( + "Creator error: only supprted with active selection") + + self.log.debug("Selection is: {}".format(self.selected_nodes)) From acde5a81fca7909820a48841f6339d8f9fdda9bf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 15:54:55 +0200 Subject: [PATCH 066/211] nuke: remove obsolete validators --- .../plugins/publish/validate_read_legacy.py | 87 -------------- .../publish/validate_write_deadline_tab.py | 53 --------- .../plugins/publish/validate_write_legacy.py | 108 ------------------ 3 files changed, 248 deletions(-) delete mode 100644 openpype/hosts/nuke/plugins/publish/validate_read_legacy.py delete mode 100644 openpype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py delete mode 100644 openpype/hosts/nuke/plugins/publish/validate_write_legacy.py diff --git a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py deleted file mode 100644 index ffd5cee710..0000000000 --- a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py +++ /dev/null @@ -1,87 +0,0 @@ -import os - -import nuke - -import toml -import pyblish.api -from bson.objectid import ObjectId -from openpype.hosts.nuke import api as napi -from openpype.pipeline import ( - discover_loader_plugins, - load_container, -) - - -class RepairReadLegacyAction(pyblish.api.Action): - - label = "Repair" - icon = "wrench" - on = "failed" - - def process(self, context, plugin): - - # Get the errored instances - failed = [] - for result in context.data["results"]: - if (result["error"] is not None and result["instance"] is not None - and result["instance"] not in failed): - failed.append(result["instance"]) - - # Apply pyblish.logic to get the instances for the plug-in - instances = pyblish.api.instances_by_plugin(failed, plugin) - - for instance in instances: - node = napi.get_instance_node(instance) - data = toml.loads(node["avalon"].value()) - data["name"] = node.name() - data["xpos"] = node.xpos() - data["ypos"] = node.ypos() - data["extension"] = os.path.splitext( - node["file"].value() - )[1][1:] - - data["connections"] = [] - for d in node.dependent(): - for i in range(d.inputs()): - if d.input(i) == node: - data["connections"].append([i, d]) - - nuke.delete(node) - - loader_name = "LoadSequence" - if data["extension"] == "mov": - loader_name = "LoadMov" - - loader_plugin = None - for Loader in discover_loader_plugins(): - if Loader.__name__ != loader_name: - continue - - loader_plugin = Loader - - load_container( - Loader=loader_plugin, - representation=ObjectId(data["representation"]) - ) - - node = nuke.toNode(data["name"]) - for connection in data["connections"]: - connection[1].setInput(connection[0], node) - - node.setXYpos(data["xpos"], data["ypos"]) - - -class ValidateReadLegacy(pyblish.api.InstancePlugin): - """Validate legacy read nodes.""" - - order = pyblish.api.ValidatorOrder - optional = True - families = ["read.legacy"] - label = "Read Legacy" - hosts = ["nuke"] - actions = [RepairReadLegacyAction] - - def process(self, instance): - - msg = "Clean up legacy read node \"{}\"".format(instance) - assert False, msg diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py b/openpype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py deleted file mode 100644 index 907577a97d..0000000000 --- a/openpype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py +++ /dev/null @@ -1,53 +0,0 @@ -import pyblish.api -import openpype.hosts.nuke.lib - - -class RepairNukeWriteDeadlineTab(pyblish.api.Action): - - label = "Repair" - icon = "wrench" - on = "failed" - - def process(self, context, plugin): - - # Get the errored instances - failed = [] - for result in context.data["results"]: - if (result["error"] is not None and result["instance"] is not None - and result["instance"] not in failed): - failed.append(result["instance"]) - - # Apply pyblish.logic to get the instances for the plug-in - instances = pyblish.api.instances_by_plugin(failed, plugin) - - for instance in instances: - group_node = [x for x in instance if x.Class() == "Group"][0] - - # Remove existing knobs. - knob_names = openpype.hosts.nuke.lib.get_deadline_knob_names() - for name, knob in group_node.knobs().items(): - if name in knob_names: - group_node.removeKnob(knob) - - openpype.hosts.nuke.lib.add_deadline_tab(group_node) - - -class ValidateNukeWriteDeadlineTab(pyblish.api.InstancePlugin): - """Ensure Deadline tab is present and current.""" - - order = pyblish.api.ValidatorOrder - label = "Deadline Tab" - hosts = ["nuke"] - optional = True - families = ["render"] - actions = [RepairNukeWriteDeadlineTab] - - def process(self, instance): - group_node = [x for x in instance if x.Class() == "Group"][0] - - knob_names = openpype.hosts.nuke.lib.get_deadline_knob_names() - missing_knobs = [] - for name in knob_names: - if name not in group_node.knobs().keys(): - missing_knobs.append(name) - assert not missing_knobs, "Missing knobs: {}".format(missing_knobs) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py deleted file mode 100644 index e9bcb08b00..0000000000 --- a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py +++ /dev/null @@ -1,108 +0,0 @@ -import toml - -import nuke - -import pyblish.api - -from openpype.pipeline import discover_creator_plugins -from openpype.pipeline.publish import RepairAction -from openpype.hosts.nuke.api.lib import get_avalon_knob_data -from openpype.hosts.nuke import api as napi - -class ValidateWriteLegacy(pyblish.api.InstancePlugin): - """Validate legacy write nodes.""" - - order = pyblish.api.ValidatorOrder - optional = True - families = ["write"] - label = "Validate Write Legacy" - hosts = ["nuke"] - actions = [RepairAction] - - def process(self, instance): - node = napi.get_instance_node(instance) - msg = "Clean up legacy write node \"{}\"".format(instance) - - if node.Class() not in ["Group", "Write"]: - return - - # test avalon knobs - family_knobs = ["ak:family", "avalon:family"] - family_test = [k for k in node.knobs().keys() if k in family_knobs] - self.log.debug("_ family_test: {}".format(family_test)) - - # test if render in family test knob - # and only one item should be available - assert len(family_test) == 1, msg + " > More avalon attributes" - assert "render" in node[family_test[0]].value() \ - or "still" in node[family_test[0]].value(), msg + \ - " > Not correct family" - # test if `file` knob in node, this way old - # non-group-node write could be detected - assert "file" not in node.knobs(), msg + \ - " > file knob should not be present" - - # check if write node is having old render targeting - assert "render_farm" not in node.knobs(), msg + \ - " > old way of setting render target" - - @classmethod - def repair(cls, instance): - node = napi.get_instance_node(instance) - - if "Write" in node.Class(): - data = toml.loads(node["avalon"].value()) - else: - data = get_avalon_knob_data(node) - - # collect reusable data - data["XYpos"] = (node.xpos(), node.ypos()) - data["input"] = node.input(0) - data["publish"] = node["publish"].value() - data["render"] = node["render"].value() - data["render_farm"] = node["render_farm"].value() - data["review"] = node["review"].value() - data["use_limit"] = node["use_limit"].value() - data["first"] = node["first"].value() - data["last"] = node["last"].value() - - family = data["family"] - cls.log.debug("_ orig node family: {}".format(family)) - - # define what family of write node should be recreated - if family == "render": - Create_name = "CreateWriteRender" - elif family == "prerender": - Create_name = "CreateWritePrerender" - elif family == "still": - Create_name = "CreateWriteStill" - - # get appropriate plugin class - creator_plugin = None - for Creator in discover_creator_plugins(): - if Creator.__name__ != Create_name: - continue - - creator_plugin = Creator - - # delete the legaci write node - nuke.delete(node) - - # create write node with creator - new_node_name = data["subset"] - creator_plugin(new_node_name, data["asset"]).process() - - node = nuke.toNode(new_node_name) - node.setXYpos(*data["XYpos"]) - node.setInput(0, data["input"]) - node["publish"].setValue(data["publish"]) - node["review"].setValue(data["review"]) - node["use_limit"].setValue(data["use_limit"]) - node["first"].setValue(data["first"]) - node["last"].setValue(data["last"]) - - # recreate render targets - if data["render"]: - node["render"].setValue("Local") - if data["render_farm"]: - node["render"].setValue("On farm") From 50dbbcdb184bdc2d96697294578ec8e73de57a91 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 16:00:00 +0200 Subject: [PATCH 067/211] nuke: no need for abstraction of getting instance node --- openpype/hosts/nuke/api/__init__.py | 2 -- openpype/hosts/nuke/api/plugin.py | 11 +---------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 8aaaff43b3..3b00ca9f6f 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -14,7 +14,6 @@ from .plugin import ( NukeWriteCreator, NukeCreatorError, OpenPypeCreator, - get_instance_node, get_instance_group_node_childs, get_colorspace_from_node ) @@ -67,7 +66,6 @@ __all__ = ( "NukeCreatorError", "OpenPypeCreator", "NukeHost", - "get_instance_node", "get_instance_group_node_childs", "get_colorspace_from_node", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 96d9b48ba6..7e3c131104 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -407,15 +407,6 @@ class OpenPypeCreator(LegacyCreator): return instance -def get_instance_node(instance): - # new publisher way - if instance.data.get("transientData"): - return instance.data["transientData"]["node"] - else: - # or backward compatible - return instance[0] - - def get_instance_group_node_childs(instance): """Return list of instance group node children @@ -425,7 +416,7 @@ def get_instance_group_node_childs(instance): Returns: list: [nuke.Node] """ - node = get_instance_node(instance) + node = instance.data["transientData"]["node"] if node.Class() != "Group": return From fcf84d1ba3c8373730f6dc68bb5b25cc9ebcb3cd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 16:00:58 +0200 Subject: [PATCH 068/211] nuke: get instance node directly form instance --- openpype/hosts/nuke/plugins/publish/collect_backdrop.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_gizmo.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_model.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_reads.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_slate_node.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_writes.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_gizmo.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_model.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_thumbnail.py | 2 +- openpype/hosts/nuke/plugins/publish/validate_asset_name.py | 4 ++-- openpype/hosts/nuke/plugins/publish/validate_backdrop.py | 2 +- openpype/hosts/nuke/plugins/publish/validate_gizmo.py | 4 ++-- .../hosts/nuke/plugins/publish/validate_output_resolution.py | 2 +- .../hosts/nuke/plugins/publish/validate_rendered_frames.py | 4 ++-- openpype/hosts/nuke/plugins/publish/validate_write_nodes.py | 4 ++-- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index dcabedf231..2d375cfb62 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -18,7 +18,7 @@ class CollectBackdrops(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug(pformat(instance.data)) - bckn = napi.get_instance_node(instance) + bckn = instance.data["transientData"]["node"] # define size of the backdrop left = bckn.xpos() diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 755c196f8e..5979cd123d 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -14,7 +14,7 @@ class CollectGizmo(pyblish.api.InstancePlugin): families = ["gizmo"] def process(self, instance): - grpn = napi.get_instance_node(instance) + grpn = instance.data["transientData"]["node"] # add family to familiess instance.data["families"].insert(0, instance.data["family"]) diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index 253121ffd4..ad3e99dfad 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -14,7 +14,7 @@ class CollectModel(pyblish.api.InstancePlugin): def process(self, instance): - geo_node = napi.get_instance_node(instance) + geo_node = instance.data["transientData"]["node"] # add family to familiess instance.data["families"].insert(0, instance.data["family"]) diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index 7390ec6884..3d14b2f231 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -18,7 +18,7 @@ class CollectNukeReads(pyblish.api.InstancePlugin): families = ["source"] def process(self, instance): - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] project_name = legacy_io.active_project() asset_name = legacy_io.Session["AVALON_ASSET"] diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index e3f24a233e..1469292664 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -12,7 +12,7 @@ class CollectSlate(pyblish.api.InstancePlugin): families = ["render"] def process(self, instance): - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] slate = next((n for n in nuke.allNodes() if "slate" in n.name().lower() diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py index 32d837f400..8122776ccc 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -18,7 +18,7 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): self.log.debug(pformat(instance.data)) instance.data.update(instance.data["creator_attributes"]) - group_node = napi.get_instance_node(instance) + group_node = instance.data["transientData"]["node"] render_target = instance.data["render_target"] family = instance.data["family"] families = instance.data["families"] diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index a3df497893..7ea9435571 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -26,7 +26,7 @@ class ExtractGizmo(publish.Extractor): def process(self, instance): tmp_nodes = [] - orig_grpn = napi.get_instance_node(instance) + orig_grpn = instance.data["transientData"]["node"] # Define extract output file path stagingdir = self.staging_dir(instance) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 5ca617f147..f44d699e1b 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -38,7 +38,7 @@ class ExtractModel(publish.Extractor): pformat(instance.data))) rm_nodes = [] - model_node = napi.get_instance_node(instance) + model_node = instance.data["transientData"]["node"] self.log.info("Crating additional nodes") subset = instance.data["subset"] diff --git a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py index dfb1b38284..a1a0e241c0 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py @@ -65,7 +65,7 @@ class ExtractThumbnail(publish.Extractor): bake_viewer_input_process_node = kwargs[ "bake_viewer_input_process"] - node = napi.get_instance_node(instance) # group node + node = instance.data["transientData"]["node"] # group node self.log.info("Creating staging dir...") if "representations" not in instance.data: diff --git a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py index 0d64da074e..230717cf18 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py +++ b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py @@ -85,7 +85,7 @@ class RepairSelectInvalidInstances(pyblish.api.Action): context_asset = context.data["assetEntity"]["name"] for instance in instances: - origin_node = napi.get_instance_node(instance) + origin_node = instance.data["transientData"]["node"] napi.lib.recreate_instance( origin_node, avalon_data={"asset": context_asset} ) @@ -112,7 +112,7 @@ class ValidateCorrectAssetName(pyblish.api.InstancePlugin): def process(self, instance): asset = instance.data.get("asset") context_asset = instance.context.data["assetEntity"]["name"] - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] msg = ( "Instance `{}` has wrong shot/asset name:\n" diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index 8ee8e631b8..e4df3430f9 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -32,7 +32,7 @@ class SelectCenterInNodeGraph(pyblish.api.Action): with napi.maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: - bdn = napi.get_instance_node(instance) + bdn = instance.data["transientData"]["node"] xC = bdn.xpos() + bdn.screenWidth() / 2 yC = bdn.ypos() + bdn.screenHeight() / 2 diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 05a4085483..1fc3726a04 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -29,7 +29,7 @@ class OpenFailedGroupNode(pyblish.api.Action): with napi.maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: - grpn = napi.get_instance_node(instance) + grpn = instance.data["transientData"]["node"] nuke.showDag(grpn) @@ -45,7 +45,7 @@ class ValidateGizmo(pyblish.api.InstancePlugin): actions = [OpenFailedGroupNode] def process(self, instance): - grpn = napi.get_instance_node(instance) + grpn = instance.data["transientData"]["node"] with grpn: connections_out = nuke.allNodes('Output') diff --git a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py index b7095e9ed7..c581e682a7 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py +++ b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py @@ -75,7 +75,7 @@ class ValidateOutputResolution(pyblish.api.InstancePlugin): ) invalid = cls.get_invalid(instance) - grp_node = napi.get_instance_node(instance) + grp_node = instance.data["transientData"]["node"] if cls.missing_msg == invalid: # make sure we are inside of the group node diff --git a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py index c1e511f534..89136124b8 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py +++ b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py @@ -24,7 +24,7 @@ class RepairActionBase(pyblish.api.Action): def repair_knob(self, instances, state): for instance in instances: - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] files_remove = [os.path.join(instance.data["outputDir"], f) for r in instance.data.get("representations", []) for f in r.get("files", []) @@ -64,7 +64,7 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin): actions = [RepairCollectionActionToLocal, RepairCollectionActionToFarm] def process(self, instance): - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] f_data = { "node_name": node.name() diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index cfd0fb3871..fc5e054fa8 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -27,7 +27,7 @@ class RepairNukeWriteNodeAction(pyblish.api.Action): or instance ) - write_group_node = napi.get_instance_node(instance) + write_group_node = instance.data["transientData"]["node"] # get write node from inside of group write_node = None for x in child_nodes: @@ -67,7 +67,7 @@ class ValidateNukeWriteNode( or instance ) - write_group_node = napi.get_instance_node(instance) + write_group_node = instance.data["transientData"]["node"] # get write node from inside of group write_node = None From c6ca7243b84a141add78af617514044c02198d07 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 16:32:56 +0200 Subject: [PATCH 069/211] nuke: fixing supporting function for resolving imageio nodes --- openpype/hosts/nuke/api/lib.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 157a2eb321..54fce77c79 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2362,26 +2362,34 @@ def get_write_node_template_attr(node): ''' Gets all defined data from presets ''' + # TODO: remove this backward compatibility for old settings + # TASK: add identifiers to settings and rename settings key + plugin_names_mapping = { + "create_write_image": "CreateWriteImage", + "create_write_prerender": "CreateWritePrerender", + "create_write_render": "CreateWriteRender" + } # get avalon data from node - avalon_knob_data = read_avalon_data(node) + node_data = get_node_data(node, INSTANCE_DATA_KNOB) + identifier = node_data["creator_identifier"] # get template data nuke_imageio_writes = get_imageio_node_setting( - node_class=avalon_knob_data["families"], - plugin_name=avalon_knob_data["creator"], - subset=avalon_knob_data["subset"] + node_class="Write", + plugin_name=plugin_names_mapping[identifier], + subset=node_data["subset"] ) - # collecting correct data - correct_data = OrderedDict() + # collecting solved data + return_data = OrderedDict() - # adding imageio knob presets - for k, v in nuke_imageio_writes.items(): - if k in ["_id", "_previous"]: - continue - correct_data[k] = v + for knob in nuke_imageio_writes["knobs"]: + knob_type = knob["type"] + knob_value = knob["value"] + new_knob_value = convert_knob_value_to_correct_type( + knob_type, knob_value) + return_data[knob["name"]] = new_knob_value - # fix badly encoded data - return fix_data_for_node_create(correct_data) + return return_data def get_dependent_nodes(nodes): From 83d60936bc597a8f6a7f174e15b72f6b4812e728 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 16:33:25 +0200 Subject: [PATCH 070/211] Nuke: fixing validator --- .../nuke/plugins/publish/validate_write_nodes.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index fc5e054fa8..ec2fba7ea7 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -5,7 +5,7 @@ from openpype.hosts.nuke.api.lib import ( set_node_knobs_from_settings, color_gui_to_int ) -from openpype.hosts.nuke import api as napi + from openpype.pipeline.publish import ( PublishXmlValidationError, OptionalPyblishPluginMixin, @@ -80,19 +80,12 @@ class ValidateNukeWriteNode( correct_data = get_write_node_template_attr(write_group_node) - if correct_data: - check_knobs = correct_data["knobs"] - else: - return - check = [] self.log.debug("__ write_node: {}".format( write_node )) - for knob_data in check_knobs: - key = knob_data["name"] - value = knob_data["value"] + for key, value in correct_data.items(): node_value = write_node[key].value() # fix type differences From 6324b0339c04cec093653e847340cccc93a46800 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 20:27:16 +0200 Subject: [PATCH 071/211] Nuke: using transient data for nodes --- openpype/hosts/nuke/plugins/publish/collect_backdrop.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_camera.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 2d375cfb62..b8317137da 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -51,7 +51,7 @@ class CollectBackdrops(pyblish.api.InstancePlugin): # make label nicer instance.data["label"] = "{0} ({1} nodes)".format( - bckn.name(), len(instance) - 1) + bckn.name(), len(instance.data["transientData"]["childNodes"])) instance.data["families"].append(instance.data["family"]) diff --git a/openpype/hosts/nuke/plugins/publish/extract_camera.py b/openpype/hosts/nuke/plugins/publish/extract_camera.py index b751bfab03..4286f71e83 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_camera.py +++ b/openpype/hosts/nuke/plugins/publish/extract_camera.py @@ -28,6 +28,7 @@ class ExtractCamera(publish.Extractor): ] def process(self, instance): + camera_node = instance.data["transientData"]["node"] handle_start = instance.context.data["handleStart"] handle_end = instance.context.data["handleEnd"] first_frame = int(nuke.root()["first_frame"].getValue()) @@ -38,7 +39,7 @@ class ExtractCamera(publish.Extractor): self.log.info("instance.data: `{}`".format( pformat(instance.data))) - rm_nodes = list() + rm_nodes = [] self.log.info("Crating additional nodes") subset = instance.data["subset"] staging_dir = self.staging_dir(instance) @@ -58,7 +59,7 @@ class ExtractCamera(publish.Extractor): with maintained_selection(): # bake camera with axeses onto word coordinate XYZ rm_n = bakeCameraWithAxeses( - nuke.toNode(instance.data["name"]), output_range) + camera_node, output_range) rm_nodes.append(rm_n) # create scene node From 76ca1e83c09759703f43471c56530428e6b9bd6a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 20:27:32 +0200 Subject: [PATCH 072/211] nuke: removing unused import --- openpype/hosts/nuke/plugins/publish/collect_backdrop.py | 1 - openpype/hosts/nuke/plugins/publish/collect_gizmo.py | 1 - openpype/hosts/nuke/plugins/publish/collect_model.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_reads.py | 1 - openpype/hosts/nuke/plugins/publish/collect_slate_node.py | 1 - openpype/hosts/nuke/plugins/publish/extract_gizmo.py | 1 - openpype/hosts/nuke/plugins/publish/extract_model.py | 1 - openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py | 1 - 8 files changed, 1 insertion(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index b8317137da..1545bb602d 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -1,7 +1,6 @@ from pprint import pformat import pyblish.api from openpype.hosts.nuke.api import lib as pnlib -from openpype.hosts.nuke import api as napi import nuke diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 5979cd123d..2cd996971a 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -1,5 +1,4 @@ import pyblish.api -from openpype.hosts.nuke import api as napi import nuke diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index ad3e99dfad..d24382b757 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -1,6 +1,6 @@ import pyblish.api import nuke -from openpype.hosts.nuke import api as napi + @pyblish.api.log class CollectModel(pyblish.api.InstancePlugin): diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index 3d14b2f231..9fad8dddf8 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -5,7 +5,6 @@ import pyblish.api from openpype.client import get_asset_by_name from openpype.pipeline import legacy_io -from openpype.hosts.nuke import api as napi @pyblish.api.log diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index 1469292664..72b0614d2b 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -1,5 +1,4 @@ import pyblish.api -from openpype.hosts.nuke import api as napi import nuke diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index 7ea9435571..4ca80e9995 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -4,7 +4,6 @@ import nuke import pyblish.api from openpype.pipeline import publish -from openpype.hosts.nuke import api as napi from openpype.hosts.nuke.api import utils as pnutils from openpype.hosts.nuke.api.lib import ( maintained_selection, diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index f44d699e1b..814d404137 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -3,7 +3,6 @@ from pprint import pformat import nuke import pyblish.api -from openpype.hosts.nuke import api as napi from openpype.pipeline import publish from openpype.hosts.nuke.api.lib import ( maintained_selection, diff --git a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py index 89136124b8..e0eb254ba1 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py +++ b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py @@ -1,7 +1,6 @@ import os import pyblish.api import clique -from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError From 2a0f4da03f7a2ec4b1a980e8f1522911ef25815b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 20:36:44 +0200 Subject: [PATCH 073/211] nuke: removing decoration which is not needed --- openpype/hosts/nuke/plugins/publish/collect_backdrop.py | 1 - openpype/hosts/nuke/plugins/publish/collect_gizmo.py | 1 - openpype/hosts/nuke/plugins/publish/collect_instance_data.py | 1 - openpype/hosts/nuke/plugins/publish/collect_model.py | 1 - openpype/hosts/nuke/plugins/publish/collect_reads.py | 2 -- openpype/hosts/nuke/plugins/publish/collect_writes.py | 1 - openpype/hosts/nuke/plugins/publish/validate_backdrop.py | 1 - openpype/hosts/nuke/plugins/publish/validate_gizmo.py | 1 - openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py | 1 - openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py | 1 - .../hosts/nuke/plugins/publish/validate_script_attributes.py | 1 - openpype/hosts/nuke/plugins/publish/validate_write_nodes.py | 1 - 12 files changed, 13 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 1545bb602d..8eaefa6854 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -4,7 +4,6 @@ from openpype.hosts.nuke.api import lib as pnlib import nuke -@pyblish.api.log class CollectBackdrops(pyblish.api.InstancePlugin): """Collect Backdrop node instance and its content """ diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 2cd996971a..c194f70f7e 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -2,7 +2,6 @@ import pyblish.api import nuke -@pyblish.api.log class CollectGizmo(pyblish.api.InstancePlugin): """Collect Gizmo (group) node instance and its content """ diff --git a/openpype/hosts/nuke/plugins/publish/collect_instance_data.py b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py index 9614ebdea6..3908aef4bc 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_instance_data.py +++ b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py @@ -2,7 +2,6 @@ import nuke import pyblish.api -@pyblish.api.log class CollectInstanceData(pyblish.api.InstancePlugin): """Collect all nodes with Avalon knob.""" diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index d24382b757..9da056052b 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -2,7 +2,6 @@ import pyblish.api import nuke -@pyblish.api.log class CollectModel(pyblish.api.InstancePlugin): """Collect Model node instance and its content """ diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index 9fad8dddf8..a1144fbcc3 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -2,12 +2,10 @@ import os import re import nuke import pyblish.api - from openpype.client import get_asset_by_name from openpype.pipeline import legacy_io -@pyblish.api.log class CollectNukeReads(pyblish.api.InstancePlugin): """Collect all read nodes.""" diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py index 8122776ccc..e18fbbdf6f 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -5,7 +5,6 @@ import pyblish.api from openpype.hosts.nuke import api as napi -@pyblish.api.log class CollectNukeWrites(pyblish.api.InstancePlugin): """Collect all write nodes.""" diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index e4df3430f9..208d4a2498 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -46,7 +46,6 @@ class SelectCenterInNodeGraph(pyblish.api.Action): nuke.zoom(2, [min(all_xC), min(all_yC)]) -@pyblish.api.log class ValidateBackdrop(pyblish.api.InstancePlugin): """ Validate amount of nodes on backdrop node in case user forgoten to add nodes above the publishing backdrop node. diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 1fc3726a04..57d7d5fc3b 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -33,7 +33,6 @@ class OpenFailedGroupNode(pyblish.api.Action): nuke.showDag(grpn) -@pyblish.api.log class ValidateGizmo(pyblish.api.InstancePlugin): """Validate amount of output nodes in gizmo (group) node""" diff --git a/openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py b/openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py index dac240ad19..c26a03f31a 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py +++ b/openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py @@ -17,7 +17,6 @@ class FixProxyMode(pyblish.api.Action): rootNode["proxy"].setValue(False) -@pyblish.api.log class ValidateProxyMode(pyblish.api.ContextPlugin): """Validate active proxy mode""" diff --git a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py index e0eb254ba1..1c22c5b9d0 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py +++ b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py @@ -4,7 +4,6 @@ import clique from openpype.pipeline import PublishXmlValidationError -@pyblish.api.log class RepairActionBase(pyblish.api.Action): on = "failed" icon = "wrench" diff --git a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py index f0632f8080..3ebc34f195 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py @@ -10,7 +10,6 @@ from openpype.hosts.nuke.api.lib import ( import nuke -@pyblish.api.log class ValidateScriptAttributes(pyblish.api.InstancePlugin): """ Validates file output. """ diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index ec2fba7ea7..c0b81f64ea 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -12,7 +12,6 @@ from openpype.pipeline.publish import ( ) -@pyblish.api.log class RepairNukeWriteNodeAction(pyblish.api.Action): label = "Repair" on = "failed" From 2fff046532f6a023b8be16ca3de405e4ea03d309 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 20:39:12 +0200 Subject: [PATCH 074/211] nuke: better logic --- .../hosts/nuke/plugins/publish/validate_gizmo.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 57d7d5fc3b..8e844247ee 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -48,22 +48,22 @@ class ValidateGizmo(pyblish.api.InstancePlugin): with grpn: connections_out = nuke.allNodes('Output') - msg_multiple_outputs = ( - "Only one outcoming connection from " - "\"{}\" is allowed").format(instance.data["name"]) - if len(connections_out) > 1: + msg_multiple_outputs = ( + "Only one outcoming connection from " + "\"{}\" is allowed").format(instance.data["name"]) + raise PublishXmlValidationError( self, msg_multiple_outputs, "multiple_outputs", {"node_name": grpn["name"].value()} ) connections_in = nuke.allNodes('Input') - msg_missing_inputs = ( - "At least one Input node has to be inside Group: " - "\"{}\"").format(instance.data["name"]) - if len(connections_in) == 0: + msg_missing_inputs = ( + "At least one Input node has to be inside Group: " + "\"{}\"").format(instance.data["name"]) + raise PublishXmlValidationError( self, msg_missing_inputs, "no_inputs", {"node_name": grpn["name"].value()} From b6107fe5611345a379440932d1020a199e69ed8a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 21:05:27 +0200 Subject: [PATCH 075/211] nuke: refactor workfile collector --- .../nuke/plugins/publish/collect_workfile.py | 41 +++++-------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py index 8b6ab5d072..7f4849be67 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -3,22 +3,19 @@ import os import nuke import pyblish.api -import openpype.api as pype -from openpype.hosts.nuke.api.lib import ( - add_publish_knob, - get_avalon_knob_data -) +import openpype.api as api from openpype.pipeline import KnownPublishError -class CollectWorkfile(pyblish.api.ContextPlugin): +class CollectWorkfile(pyblish.api.InstancePlugin): """Collect current script for publish.""" - order = pyblish.api.CollectorOrder - 0.50 + order = pyblish.api.CollectorOrder - 0.499 label = "Collect Workfile" hosts = ['nuke'] + families = ["workfile"] - def process(self, context): # sourcery skip: avoid-builtin-shadow + def process(self, instance): # sourcery skip: avoid-builtin-shadow root = nuke.root() current_file = os.path.normpath(nuke.root().name()) @@ -29,23 +26,16 @@ class CollectWorkfile(pyblish.api.ContextPlugin): "Use workfile tool to manage the name correctly." ) - knob_data = get_avalon_knob_data(root) - - add_publish_knob(root) - - family = "workfile" - task = os.getenv("AVALON_TASK", None) # creating instances per write node staging_dir = os.path.dirname(current_file) base_name = os.path.basename(current_file) - subset = family + task.capitalize() # Get frame range first_frame = int(root["first_frame"].getValue()) last_frame = int(root["last_frame"].getValue()) - handle_start = int(knob_data.get("handleStart", 0)) - handle_end = int(knob_data.get("handleEnd", 0)) + handle_start = instance.data["handleStart"] + handle_end = instance.data["handleEnd"] # Get format format = root['format'].value() @@ -53,33 +43,27 @@ class CollectWorkfile(pyblish.api.ContextPlugin): resolution_height = format.height() pixel_aspect = format.pixelAspect() - # Create instance - instance = context.create_instance(subset) - instance.add(root) - script_data = { - "asset": os.getenv("AVALON_ASSET", None), "frameStart": first_frame + handle_start, "frameEnd": last_frame - handle_end, "resolutionWidth": resolution_width, "resolutionHeight": resolution_height, "pixelAspect": pixel_aspect, - # backward compatibility + # backward compatibility handles "handles": handle_start, - "handleStart": handle_start, "handleEnd": handle_end, "step": 1, "fps": root['fps'].value(), "currentFile": current_file, - "version": int(pype.get_version_from_path(current_file)), + "version": int(api.get_version_from_path(current_file)), "host": pyblish.api.current_host(), "hostVersion": nuke.NUKE_VERSION_STRING } - context.data.update(script_data) + instance.context.data.update(script_data) # creating representation representation = { @@ -91,12 +75,7 @@ class CollectWorkfile(pyblish.api.ContextPlugin): # creating instance data instance.data.update({ - "subset": subset, - "label": base_name, "name": base_name, - "publish": root.knob('publish').value(), - "family": family, - "families": [family], "representations": [representation] }) From cdd11eae8f2acdc4c8172eb03ef106a2a42b0f40 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 21:34:44 +0200 Subject: [PATCH 076/211] Deadline: nuke submitter gets node with new way --- .../modules/deadline/plugins/publish/submit_nuke_deadline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py b/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py index b09d2935ab..083c2bcd78 100644 --- a/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -40,7 +40,7 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin): instance.data["toBeRenderedOn"] = "deadline" families = instance.data["families"] - node = instance[0] + node = instance.data["transientData"]["node"] context = instance.context # get default deadline webservice url from deadline module From f8b4183b49b7b5d83af574f1ad78702a9ed7d5a2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 21:35:01 +0200 Subject: [PATCH 077/211] nuke: fixing review and frames conditions --- .../nuke/plugins/publish/collect_writes.py | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py index e18fbbdf6f..3054e5a30c 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -15,7 +15,8 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug(pformat(instance.data)) - instance.data.update(instance.data["creator_attributes"]) + creator_attributes = instance.data["creator_attributes"] + instance.data.update(creator_attributes) group_node = instance.data["transientData"]["node"] render_target = instance.data["render_target"] @@ -26,12 +27,8 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): instance.data["families"].append( "{}.{}".format(family, render_target) ) - # add additional keys to farm targeted - if render_target == "farm": - # Farm rendering - self.log.info("flagged for farm render") - instance.data["transfer"] = False - instance.data["farm"] = True + if instance.data.get("review"): + instance.data["families"].append("review") child_nodes = napi.get_instance_group_node_childs(instance) instance.data["transientData"]["childNodes"] = child_nodes @@ -71,8 +68,7 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): self.log.debug('output dir: {}'.format(output_dir)) - if render_target == "frame": - + if render_target == "frames": representation = { 'name': ext, 'ext': ext, @@ -133,6 +129,21 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): representation['files'] = collected_frames instance.data["representations"].append(representation) + self.log.info("Publishing rendered frames ...") + + elif render_target == "farm": + farm_priority = creator_attributes.get("farm_priority") + farm_chunk = creator_attributes.get("farm_chunk") + farm_concurency = creator_attributes.get("farm_concurency") + instance.data.update({ + "deadlineChunkSize": farm_chunk or 1, + "deadlinePriority": farm_priority or 50, + "deadlineConcurrentTasks": farm_concurency or 0 + }) + # Farm rendering + instance.data["transfer"] = False + instance.data["farm"] = True + self.log.info("Farm rendering ON ...") # get colorspace and add to version data colorspace = napi.get_colorspace_from_node(write_node) @@ -140,28 +151,12 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): "colorspace": colorspace } - # get deadline related attributes - dl_chunk_size = 1 - if "deadlineChunkSize" in group_node.knobs(): - dl_chunk_size = group_node["deadlineChunkSize"].value() - - dl_priority = 50 - if "deadlinePriority" in group_node.knobs(): - dl_priority = group_node["deadlinePriority"].value() - - dl_concurrent_tasks = 0 - if "deadlineConcurrentTasks" in group_node.knobs(): - dl_concurrent_tasks = group_node["deadlineConcurrentTasks"].value() - instance.data.update({ "versionData": version_data, "path": write_file_path, "outputDir": output_dir, "ext": ext, - "colorspace": colorspace, - "deadlineChunkSize": dl_chunk_size, - "deadlinePriority": dl_priority, - "deadlineConcurrentTasks": dl_concurrent_tasks + "colorspace": colorspace }) if family == "render": From 462e141ab00ec65454af1d932130b6c70e7c31aa Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 19 Oct 2022 17:41:36 +0200 Subject: [PATCH 078/211] removing old code --- openpype/hosts/nuke/plugins/publish/validate_knobs.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_knobs.py b/openpype/hosts/nuke/plugins/publish/validate_knobs.py index 1d853f72b5..ee8a824d8f 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_knobs.py +++ b/openpype/hosts/nuke/plugins/publish/validate_knobs.py @@ -62,16 +62,7 @@ class ValidateKnobs(pyblish.api.ContextPlugin): for instance in context: # Filter publisable instances. - if ( - instance.data.get("publish") - and instance.data["publish"] is False - ): - continue - - if ( - instance.data.get("active") - and instance.data["active"] is False - ): + if not instance.data.get("active"): continue # Filter families. From a7aff0e50cf46471497968646425d0fac28830ff Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 19 Oct 2022 17:46:01 +0200 Subject: [PATCH 079/211] nuke: removing old logic code --- openpype/hosts/nuke/plugins/publish/validate_knobs.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_knobs.py b/openpype/hosts/nuke/plugins/publish/validate_knobs.py index ee8a824d8f..db21cdc7c5 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_knobs.py +++ b/openpype/hosts/nuke/plugins/publish/validate_knobs.py @@ -61,17 +61,11 @@ class ValidateKnobs(pyblish.api.ContextPlugin): invalid_knobs = [] for instance in context: - # Filter publisable instances. - if not instance.data.get("active"): - continue # Filter families. families = [instance.data["family"]] families += instance.data.get("families", []) - if not families: - continue - # Get all knobs to validate. knobs = {} for family in families: From 71c2458d6a1c582aeee991842390bc12ffa21ebc Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 10:36:38 +0200 Subject: [PATCH 080/211] nuke: fix tab --- openpype/hosts/nuke/api/lib.py | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 54fce77c79..fd9c0de9c0 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2726,29 +2726,29 @@ def recreate_instance(origin_node, avalon_data=None): def add_scripts_menu(): - try: - from scriptsmenu import launchfornuke - except ImportError: - log.warning( - "Skipping studio.menu install, because " - "'scriptsmenu' module seems unavailable." - ) - return + try: + from scriptsmenu import launchfornuke + except ImportError: + log.warning( + "Skipping studio.menu install, because " + "'scriptsmenu' module seems unavailable." + ) + return - # load configuration of custom menu - project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) - config = project_settings["nuke"]["scriptsmenu"]["definition"] - _menu = project_settings["nuke"]["scriptsmenu"]["name"] + # load configuration of custom menu + project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) + config = project_settings["nuke"]["scriptsmenu"]["definition"] + _menu = project_settings["nuke"]["scriptsmenu"]["name"] - if not config: - log.warning("Skipping studio menu, no definition found.") - return + if not config: + log.warning("Skipping studio menu, no definition found.") + return - # run the launcher for Maya menu - studio_menu = launchfornuke.main(title=_menu.title()) + # run the launcher for Maya menu + studio_menu = launchfornuke.main(title=_menu.title()) - # apply configuration - studio_menu.build_from_configuration(studio_menu, config) + # apply configuration + studio_menu.build_from_configuration(studio_menu, config) def add_scripts_gizmo(): From bb3105cefb1bc10e6e0841c59303e3f703e47460 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 16:25:47 +0200 Subject: [PATCH 081/211] Nuke: make fallback in case node is erased manually --- openpype/hosts/nuke/api/plugin.py | 44 ++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 7e3c131104..88da6c5eb2 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -205,6 +205,13 @@ class NukeCreator(NewCreator): for created_inst, _changes in update_list: instance_node = created_inst.transient_data["node"] + # in case node is not existing anymore (user erased it manually) + try: + instance_node.fullName() + except ValueError: + self.remove_instances([created_inst]) + continue + set_node_data( instance_node, INSTANCE_DATA_KNOB, @@ -1114,6 +1121,8 @@ def convert_to_valid_instaces(): nuke.Root()["project_directory"].setValue(os.path.dirname(path)) nuke.Root().setModified(False) + _remove_old_knobs(nuke.Root()) + # loop all nodes and convert for node in nuke.allNodes(recurseGroups=True): transfer_data = { @@ -1188,24 +1197,29 @@ def convert_to_valid_instaces(): creator_attr["farm_concurency"] = ( node["deadlineConcurrentTasks"].value()) - remove_knobs = [ - "review", "publish", "render", "suspend_publish", "warn", "divd", - "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", - "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" - ] - print(node.name()) + _remove_old_knobs(node) - # remove all old knobs - for knob in node.allKnobs(): - try: - if knob.name() in remove_knobs: - node.removeKnob(knob) - elif "avalon" in knob.name(): - node.removeKnob(knob) - except ValueError: - pass # add new instance knob with transfer data set_node_data( node, INSTANCE_DATA_KNOB, transfer_data) nuke.scriptSave() + + +def _remove_old_knobs(node): + remove_knobs = [ + "review", "publish", "render", "suspend_publish", "warn", "divd", + "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", + "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" + ] + print(node.name()) + + # remove all old knobs + for knob in node.allKnobs(): + try: + if knob.name() in remove_knobs: + node.removeKnob(knob) + elif "avalon" in knob.name(): + node.removeKnob(knob) + except ValueError: + pass From d8bda695ce183950c320fcf4f04ae2fc983a8298 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 16:30:27 +0200 Subject: [PATCH 082/211] Nuke: Creator depricated --- openpype/hosts/nuke/api/pipeline.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 258b09f7a8..700db9a8ed 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -228,6 +228,11 @@ def _install_menu(): ) menu.addSeparator() + menu.addCommand( + "Create... [depricated]", + lambda: nuke.message( + "New position is in \"Publish...\" and \"Create\" tab") + ) menu.addCommand( "Publish...", host_tools.show_publisher From 88a1e11faee664d7740a28f417e3d590fa49104e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 16:52:32 +0200 Subject: [PATCH 083/211] nuke: shortcut could be set in project overrides --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 700db9a8ed..7376166029 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -365,7 +365,7 @@ def add_shortcuts_from_presets(): item_label = menu_label_mapping[command_name] menuitem = menu.findItem(item_label) menuitem.setShortcut(shortcut_str) - except AttributeError as e: + except (AttributeError, KeyError) as e: log.error(e) From dc9a355965afb1b0149df8b1cd6c05241150187b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 17:49:15 +0200 Subject: [PATCH 084/211] Nuke: adding fallbacks if settings have overrides --- openpype/hosts/nuke/api/plugin.py | 13 ++++++++----- .../hosts/nuke/plugins/create/create_write_image.py | 11 +++++++++++ .../nuke/plugins/create/create_write_prerender.py | 13 +++++++++++++ .../nuke/plugins/create/create_write_render.py | 10 ++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 88da6c5eb2..b8fc54e443 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -358,12 +358,15 @@ class NukeWriteCreator(NukeCreator): plugin_settings = self.get_creator_settings(project_settings) # individual attributes - self.instance_attributes = plugin_settings[ - "instance_attributes"] + self.instance_attributes = plugin_settings.get( + "instance_attributes") or self.instance_attributes self.prenodes = plugin_settings["prenodes"] - self.default_variants = plugin_settings["default_variants"] - self.temp_rendering_path_template = plugin_settings[ - "temp_rendering_path_template"] + self.default_variants = plugin_settings.get( + "default_variants") or self.default_variants + self.temp_rendering_path_template = ( + plugin_settings.get("temp_rendering_path_template") + or self.temp_rendering_path_template + ) class OpenPypeCreator(LegacyCreator): diff --git a/openpype/hosts/nuke/plugins/create/create_write_image.py b/openpype/hosts/nuke/plugins/create/create_write_image.py index e9ff33a32b..cf70063abc 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_image.py +++ b/openpype/hosts/nuke/plugins/create/create_write_image.py @@ -20,6 +20,17 @@ class CreateWriteImage(napi.NukeWriteCreator): family = "image" icon = "sign-out" + instance_attributes = [ + "use_range_limit" + ] + default_variants = [ + "StillFrame", + "MPFrame", + "LayoutFrame" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") + def get_pre_create_attr_defs(self): attr_defs = [ BoolDef( diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index b7d0f4ade9..daa2319c4b 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -20,6 +20,19 @@ class CreateWritePrerender(napi.NukeWriteCreator): family = "prerender" icon = "sign-out" + instance_attributes = [ + "use_range_limit" + ] + default_variants = [ + "Key01", + "Bg01", + "Fg01", + "Branch01", + "Part01" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") + def get_pre_create_attr_defs(self): attr_defs = [ BoolDef( diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 3d96e8c13b..85133458d1 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -20,6 +20,16 @@ class CreateWriteRender(napi.NukeWriteCreator): family = "render" icon = "sign-out" + instance_attributes = [ + "reviewable" + ] + default_variants = [ + "Main", + "Mask" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") + def get_pre_create_attr_defs(self): attr_defs = [ BoolDef( From 6ed91d4634aea05d7ed6d33631482335d9691772 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 26 Oct 2022 11:38:49 +0200 Subject: [PATCH 085/211] missing dot --- openpype/hosts/nuke/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 974afffc72..7237b8f398 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -692,7 +692,7 @@ def get_nuke_imageio_settings(): Context.project_name)["nuke"]["imageio"] # backward compatibility for project started before 3.10 - # those are still having `__legacy__` knob types + # those are still having `__legacy__` knob types. if not project_imageio["enabled"]: return get_anatomy_settings(Context.project_name)["imageio"]["nuke"] From c63c9d5fb7a8fe96424882e52abb8fee6fd5371d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 26 Oct 2022 12:22:32 +0200 Subject: [PATCH 086/211] integrate creator legacy convertor plugin --- openpype/hosts/nuke/api/pipeline.py | 4 -- openpype/hosts/nuke/api/plugin.py | 15 ++++-- .../nuke/plugins/create/convert_legacy.py | 49 +++++++++++++++++++ 3 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 openpype/hosts/nuke/plugins/create/convert_legacy.py diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index f682247143..2622a45772 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -302,10 +302,6 @@ def _install_menu(): lambda: host_tools.show_experimental_tools_dialog(parent=main_window) ) menu.addSeparator() - menu.addCommand( - "Convert old publishing instances", - plugin.convert_to_valid_instaces - ) # add reload pipeline only in debug mode if bool(os.getenv("NUKE_DEBUG")): menu.addSeparator() diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index a2560317e6..1ef5b47bd7 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -32,6 +32,7 @@ from .lib import ( Knobby, check_subsetname_exists, maintained_selection, + get_avalon_knob_data, set_avalon_knob_data, add_publish_knob, get_nuke_imageio_settings, @@ -1135,16 +1136,22 @@ def convert_to_valid_instaces(): } return mapping[family] - from openpype.hosts.nuke.api.lib import ( - get_avalon_knob_data - ) from openpype.hosts.nuke.api import workio task_name = legacy_io.Session["AVALON_TASK"] # save into new workfile current_file = workio.current_file() - new_workfile = current_file[:-3] + "_publisherConvert" + current_file[-3:] + + # add file suffex if not + if "_publisherConvert" not in current_file: + new_workfile = ( + current_file[:-3] + + "_publisherConvert" + + current_file[-3:] + ) + else: + new_workfile = current_file path = new_workfile.replace("\\", "/") nuke.scriptSaveAs(new_workfile, overwrite=1) diff --git a/openpype/hosts/nuke/plugins/create/convert_legacy.py b/openpype/hosts/nuke/plugins/create/convert_legacy.py new file mode 100644 index 0000000000..08bf66309e --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/convert_legacy.py @@ -0,0 +1,49 @@ +from openpype.pipeline.create.creator_plugins import SubsetConvertorPlugin +from openpype.hosts.nuke.api.lib import ( + INSTANCE_DATA_KNOB, + get_node_data, + get_avalon_knob_data +) +from openpype.hosts.nuke.api.plugin import convert_to_valid_instaces + +import nuke + + +class LegacyConverted(SubsetConvertorPlugin): + identifier = "legacy.converter" + + def find_instances(self): + + legacy_found = False + # search for first available legacy item + for node in nuke.allNodes(recurseGroups=True): + + if node.Class() in ["Viewer", "Dot"]: + continue + + if get_node_data(node, INSTANCE_DATA_KNOB): + continue + + # get data from avalon knob + avalon_knob_data = get_avalon_knob_data( + node, ["avalon:", "ak:"]) + + if not avalon_knob_data: + continue + + if avalon_knob_data["id"] != "pyblish.avalon.instance": + continue + + # catch and break + legacy_found = True + break + + if legacy_found: + # if not item do not add legacy instance convertor + self.add_convertor_item("Convert legacy instances") + + def convert(self): + # loop all instances and convert them + convert_to_valid_instaces() + # remove legacy item if all is fine + self.remove_convertor_item() From b6c6fad10e029552c48ae61c4e90c487b2b27d76 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 26 Oct 2022 12:31:53 +0200 Subject: [PATCH 087/211] remove unused imports --- openpype/hosts/nuke/api/pipeline.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 2622a45772..eaab98f292 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -42,8 +42,7 @@ from .lib import ( add_scripts_menu, add_scripts_gizmo, get_node_data, - set_node_data, - update_node_data + set_node_data ) from .workfile_template_builder import ( NukePlaceholderLoadPlugin, @@ -60,7 +59,6 @@ from .workio import ( work_root, current_file ) -from openpype.hosts.nuke.api import plugin log = Logger.get_logger(__name__) From 8a2c10e3d1ed558054e204672b219d28c327e0da Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 11:20:21 +0200 Subject: [PATCH 088/211] Nuke: rewrite collect workfile so we are able to disable its publishing --- .../plugins/publish/collect_context_data.py | 69 +++++++++++++++++++ .../nuke/plugins/publish/collect_workfile.py | 51 +------------- 2 files changed, 72 insertions(+), 48 deletions(-) create mode 100644 openpype/hosts/nuke/plugins/publish/collect_context_data.py diff --git a/openpype/hosts/nuke/plugins/publish/collect_context_data.py b/openpype/hosts/nuke/plugins/publish/collect_context_data.py new file mode 100644 index 0000000000..5a1cdcf49e --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_context_data.py @@ -0,0 +1,69 @@ +import os +import nuke +import pyblish.api +import openpype.api as api +import openpype.hosts.nuke.api as napi +from openpype.pipeline import KnownPublishError + + +class CollectContextData(pyblish.api.ContextPlugin): + """Collect current context publish.""" + + order = pyblish.api.CollectorOrder - 0.499 + label = "Collect context data" + hosts = ['nuke'] + + def process(self, context): # sourcery skip: avoid-builtin-shadow + root_node = nuke.root() + + current_file = os.path.normpath(root_node.name()) + + if current_file.lower() == "root": + raise KnownPublishError( + "Workfile is not correct file name. \n" + "Use workfile tool to manage the name correctly." + ) + + # Get frame range + first_frame = int(root_node["first_frame"].getValue()) + last_frame = int(root_node["last_frame"].getValue()) + + # get instance data from root + root_instance_context = napi.get_node_data( + root_node, napi.INSTANCE_DATA_KNOB + ) + + handle_start = root_instance_context["handleStart"] + handle_end = root_instance_context["handleEnd"] + + # Get format + format = root_node['format'].value() + resolution_width = format.width() + resolution_height = format.height() + pixel_aspect = format.pixelAspect() + + script_data = { + "frameStart": first_frame + handle_start, + "frameEnd": last_frame - handle_end, + "resolutionWidth": resolution_width, + "resolutionHeight": resolution_height, + "pixelAspect": pixel_aspect, + + # backward compatibility handles + "handles": handle_start, + "handleStart": handle_start, + "handleEnd": handle_end, + "step": 1, + "fps": root_node['fps'].value(), + + "currentFile": current_file, + "version": int(api.get_version_from_path(current_file)), + + "host": pyblish.api.current_host(), + "hostVersion": nuke.NUKE_VERSION_STRING + } + + context.data["scriptData"] = script_data + context.data.update(script_data) + + self.log.info('Context from Nuke script collected') diff --git a/openpype/hosts/nuke/plugins/publish/collect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py index 7f4849be67..54c77b1e4e 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -1,70 +1,25 @@ import os - import nuke - import pyblish.api -import openpype.api as api -from openpype.pipeline import KnownPublishError class CollectWorkfile(pyblish.api.InstancePlugin): """Collect current script for publish.""" - order = pyblish.api.CollectorOrder - 0.499 + order = pyblish.api.CollectorOrder - 0.498 label = "Collect Workfile" hosts = ['nuke'] families = ["workfile"] def process(self, instance): # sourcery skip: avoid-builtin-shadow - root = nuke.root() + script_data = instance.context.data["scriptData"] current_file = os.path.normpath(nuke.root().name()) - if current_file.lower() == "root": - raise KnownPublishError( - "Workfile is not correct file name. \n" - "Use workfile tool to manage the name correctly." - ) - # creating instances per write node staging_dir = os.path.dirname(current_file) base_name = os.path.basename(current_file) - # Get frame range - first_frame = int(root["first_frame"].getValue()) - last_frame = int(root["last_frame"].getValue()) - - handle_start = instance.data["handleStart"] - handle_end = instance.data["handleEnd"] - - # Get format - format = root['format'].value() - resolution_width = format.width() - resolution_height = format.height() - pixel_aspect = format.pixelAspect() - - script_data = { - "frameStart": first_frame + handle_start, - "frameEnd": last_frame - handle_end, - "resolutionWidth": resolution_width, - "resolutionHeight": resolution_height, - "pixelAspect": pixel_aspect, - - # backward compatibility handles - "handles": handle_start, - "handleStart": handle_start, - "handleEnd": handle_end, - "step": 1, - "fps": root['fps'].value(), - - "currentFile": current_file, - "version": int(api.get_version_from_path(current_file)), - - "host": pyblish.api.current_host(), - "hostVersion": nuke.NUKE_VERSION_STRING - } - instance.context.data.update(script_data) - # creating representation representation = { 'name': 'nk', @@ -82,4 +37,4 @@ class CollectWorkfile(pyblish.api.InstancePlugin): # adding basic script data instance.data.update(script_data) - self.log.info('Publishing script version') + self.log.info("Collect script version") From fc87bf19e8e79ec30cfd3fa058f5a2bb3020a848 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 12:00:52 +0200 Subject: [PATCH 089/211] nuke: fixing extractor for transient data --- .../hosts/nuke/plugins/publish/extract_ouput_node.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py index eb9bc0b429..6067e6cf6b 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py +++ b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py @@ -16,9 +16,12 @@ class CreateOutputNode(pyblish.api.ContextPlugin): def process(self, context): # capture selection state with maintained_selection(): - active_node = [node for inst in context - for node in inst - if "ak:family" in node.knobs()] + + active_node = [ + inst.data.get("transientData", {}).get("node") + for inst in context + if inst.data.get("transientData", {}).get("node") + ] if active_node: self.log.info(active_node) From 125fafa79006792db0ba61c7c13a04e320ac4853 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:10:47 +0200 Subject: [PATCH 090/211] Nuke: depricated function in lib --- openpype/hosts/nuke/api/lib.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 7237b8f398..869843e711 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -477,7 +477,7 @@ def set_avalon_knob_data(node, data=None, prefix="avalon:"): return node -def get_avalon_knob_data(node, prefix="avalon:"): +def get_avalon_knob_data(node, prefix="avalon:", create=True): """[DEPRICATED] Gets a data from nodes's avalon knob Arguments: @@ -506,8 +506,11 @@ def get_avalon_knob_data(node, prefix="avalon:"): except NameError as e: # if it doesn't then create it log.debug("Creating avalon knob: `{}`".format(e)) - node = set_avalon_knob_data(node) - return get_avalon_knob_data(node) + if create: + node = set_avalon_knob_data(node) + return get_avalon_knob_data(node) + else: + return {} # get data from filtered knobs data.update({k.replace(p, ''): node[k].value() @@ -2660,6 +2663,7 @@ def process_workfile_builder(): open_file(last_workfile_path) +@deprecated def recreate_instance(origin_node, avalon_data=None): """Recreate input instance to different data From 95bf35b6fab3b0f7f9aedd7147739aec1020dc86 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:11:25 +0200 Subject: [PATCH 091/211] nuke: improving list instances --- openpype/hosts/nuke/api/pipeline.py | 8 ++--- openpype/hosts/nuke/api/plugin.py | 30 +++++++++---------- .../nuke/plugins/create/convert_legacy.py | 2 +- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index eaab98f292..0f49419903 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -490,7 +490,6 @@ def ls(): nodes = [n for n in all_nodes] for n in nodes: - log.debug("name: `{}`".format(n.name())) container = parse_container(n) if container: yield container @@ -513,9 +512,9 @@ def list_instances(creator_id=None): try: if node["disable"].value(): continue - except Exception as _exc: - log.debug("Node {} have no disable knob - {}".format( - node.fullName(), _exc)) + except NameError: + # pass if disable knob doesn't exist + pass # get data from avalon knob instance_data = get_node_data( @@ -527,7 +526,6 @@ def list_instances(creator_id=None): if instance_data["id"] != "pyblish.avalon.instance": continue - log.debug("_ creator_id: {}".format(creator_id)) if creator_id and instance_data["creator_identifier"] != creator_id: continue diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 1ef5b47bd7..1f102a2de5 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,4 +1,3 @@ -from pprint import pformat import nuke import re import os @@ -6,7 +5,7 @@ import sys import six import random import string -from collections import OrderedDict +from collections import OrderedDict, defaultdict from abc import abstractmethod from openpype.client import ( @@ -49,6 +48,18 @@ from .pipeline import ( ) +def _collect_and_cache_nodes(creator): + key = "openpype.nuke.nodes" + if key not in creator.collection_shared_data: + instances_by_identifier = defaultdict(list) + for item in list_instances(): + _, instance_data = item + identifier = instance_data["creator_identifier"] + instances_by_identifier[identifier].append(item) + creator.collection_shared_data[key] = instances_by_identifier + return creator.collection_shared_data[key] + + class NukeCreatorError(CreatorError): pass @@ -150,7 +161,6 @@ class NukeCreator(NewCreator): else: self.selected_nodes = [] - self.log.debug("Selection is: {}".format(self.selected_nodes)) def create(self, subset_name, instance_data, pre_create_data): @@ -192,11 +202,8 @@ class NukeCreator(NewCreator): sys.exc_info()[2]) def collect_instances(self): - for (node, data) in list_instances(creator_id=self.identifier): - self.log.debug("_" * 50) - self.log.debug("_ self.identifier: `{}`".format(self.identifier)) - self.log.debug("_ data: `{}`".format(pformat(data))) - + cached_instances = _collect_and_cache_nodes(self) + for (node, data) in cached_instances[self.identifier]: created_instance = CreatedInstance.from_existing( data, self ) @@ -555,7 +562,6 @@ class ExporterReview(object): def get_file_info(self): if self.collection: - self.log.debug("Collection: `{}`".format(self.collection)) # get path self.fname = os.path.basename(self.collection.format( "{head}{padding}{tail}")) @@ -690,7 +696,6 @@ class ExporterReviewLut(ExporterReview): # connect self._temp_nodes.append(cms_node) self.previous_node = cms_node - self.log.debug("CMSTestPattern... `{}`".format(self._temp_nodes)) if bake_viewer_process: # Node View Process @@ -723,8 +728,6 @@ class ExporterReviewLut(ExporterReview): # connect gen_lut_node.setInput(0, self.previous_node) self._temp_nodes.append(gen_lut_node) - self.log.debug("GenerateLUT... `{}`".format(self._temp_nodes)) - # ---------- end nodes creation # Export lut file @@ -738,8 +741,6 @@ class ExporterReviewLut(ExporterReview): # ---------- generate representation data self.get_representation_data() - self.log.debug("Representation... `{}`".format(self.data)) - # ---------- Clean up self.clean_nodes() @@ -990,7 +991,6 @@ class AbstractWriteRender(OpenPypeCreator): self.data = data self.nodes = nuke.selectedNodes() - self.log.debug("_ self.data: '{}'".format(self.data)) def process(self): diff --git a/openpype/hosts/nuke/plugins/create/convert_legacy.py b/openpype/hosts/nuke/plugins/create/convert_legacy.py index 08bf66309e..d7341c625f 100644 --- a/openpype/hosts/nuke/plugins/create/convert_legacy.py +++ b/openpype/hosts/nuke/plugins/create/convert_legacy.py @@ -26,7 +26,7 @@ class LegacyConverted(SubsetConvertorPlugin): # get data from avalon knob avalon_knob_data = get_avalon_knob_data( - node, ["avalon:", "ak:"]) + node, ["avalon:", "ak:"], create=False) if not avalon_knob_data: continue From a16d7c95b76eadde20f40bfb2c436aa539af1f8f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:12:03 +0200 Subject: [PATCH 092/211] removing logging --- openpype/hosts/nuke/plugins/create/create_camera.py | 2 -- openpype/hosts/nuke/plugins/create/create_model.py | 2 -- openpype/hosts/nuke/plugins/create/create_source.py | 2 -- openpype/hosts/nuke/plugins/create/workfile_creator.py | 2 -- 4 files changed, 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index c559aa2756..ac1a0c7db7 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -62,5 +62,3 @@ class CreateCamera(NukeCreator): NukeCreatorError("Creator error: Select only one camera node") else: self.selected_nodes = [] - - self.log.debug("Selection is: {}".format(self.selected_nodes)) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index a1a96bf412..22b28cb7ce 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -63,5 +63,3 @@ class CreateModel(NukeCreator): NukeCreatorError("Creator error: Select only one camera node") else: self.selected_nodes = [] - - self.log.debug("Selection is: {}".format(self.selected_nodes)) diff --git a/openpype/hosts/nuke/plugins/create/create_source.py b/openpype/hosts/nuke/plugins/create/create_source.py index 48f9f86219..35fe42c16b 100644 --- a/openpype/hosts/nuke/plugins/create/create_source.py +++ b/openpype/hosts/nuke/plugins/create/create_source.py @@ -89,5 +89,3 @@ class CreateSource(NukeCreator): else: NukeCreatorError( "Creator error: only supprted with active selection") - - self.log.debug("Selection is: {}".format(self.selected_nodes)) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index ae05cee99f..31068c1828 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -22,7 +22,6 @@ class WorkfileCreator(AutoCreator): instance_data = api.get_node_data( root_node, api.INSTANCE_DATA_KNOB ) - self.log.debug("__ instance_data: {}".format(instance_data)) project_name = legacy_io.Session["AVALON_PROJECT"] asset_name = legacy_io.Session["AVALON_ASSET"] @@ -34,7 +33,6 @@ class WorkfileCreator(AutoCreator): self.default_variant, task_name, asset_doc, project_name, host_name ) - self.log.debug("__ subset_name: {}".format(subset_name)) instance_data.update({ "asset": asset_name, "task": task_name, From b400a604f032de1c8ae32db00b4536a4b083dbac Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:12:13 +0200 Subject: [PATCH 093/211] typo --- .../hosts/nuke/plugins/publish/help/validate_asset_name.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml b/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml index 1097909a5f..0422917e9c 100644 --- a/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml +++ b/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml @@ -1,7 +1,7 @@ - Shot/Asset mame + Shot/Asset name ## Invalid Shot/Asset name in subset From ebb07f928435146e08ad9014920afd740a0bb13e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:12:31 +0200 Subject: [PATCH 094/211] nuke: fixing validators --- .../plugins/publish/validate_asset_name.py | 19 +++---- .../publish/validate_script_attributes.py | 54 ++++--------------- 2 files changed, 20 insertions(+), 53 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py index 230717cf18..f6822bee45 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py +++ b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py @@ -2,11 +2,10 @@ """Validate if instance asset is the same as context asset.""" from __future__ import absolute_import -import nuke import pyblish.api import openpype.hosts.nuke.api.lib as nlib -from openpype.hosts.nuke import api as napi + from openpype.pipeline.publish import ( ValidateContentsOrder, PublishXmlValidationError, @@ -51,9 +50,10 @@ class SelectInvalidInstances(pyblish.api.Action): self.deselect() def select(self, instances): - nlib.select_nodes( - [nuke.toNode(str(x)) for x in instances] - ) + for inst in instances: + if inst.data.get("transientData", {}).get("node"): + select_node = inst.data["transientData"]["node"] + select_node["selected"].setValue(True) def deselect(self): nlib.reset_selection() @@ -82,13 +82,14 @@ class RepairSelectInvalidInstances(pyblish.api.Action): # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) + self.log.debug(instances) context_asset = context.data["assetEntity"]["name"] for instance in instances: - origin_node = instance.data["transientData"]["node"] - napi.lib.recreate_instance( - origin_node, avalon_data={"asset": context_asset} - ) + node = instance.data["transientData"]["node"] + node_data = nlib.get_node_data(node, nlib.INSTANCE_DATA_KNOB) + node_data["asset"] = context_asset + nlib.set_node_data(node, nlib.INSTANCE_DATA_KNOB, node_data) class ValidateCorrectAssetName(pyblish.api.InstancePlugin): diff --git a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py index 3ebc34f195..f932ef2c40 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py @@ -1,13 +1,10 @@ -from pprint import pformat +from copy import deepcopy import pyblish.api - from openpype.pipeline import PublishXmlValidationError from openpype.pipeline.publish import RepairAction from openpype.hosts.nuke.api.lib import ( - get_avalon_knob_data, WorkfileSettings ) -import nuke class ValidateScriptAttributes(pyblish.api.InstancePlugin): @@ -21,14 +18,9 @@ class ValidateScriptAttributes(pyblish.api.InstancePlugin): actions = [RepairAction] def process(self, instance): - root = nuke.root() - knob_data = get_avalon_knob_data(root) + script_data = deepcopy(instance.context.data["scriptData"]) + asset = instance.data["assetEntity"] - # get asset data frame values - frame_start = asset["data"]["frameStart"] - frame_end = asset["data"]["frameEnd"] - handle_start = asset["data"]["handleStart"] - handle_end = asset["data"]["handleEnd"] # These attributes will be checked attributes = [ @@ -47,37 +39,11 @@ class ValidateScriptAttributes(pyblish.api.InstancePlugin): for attr in attributes if attr in asset["data"] } - # fix float to max 4 digints (only for evaluating) - fps_data = float("{0:.4f}".format( - asset_attributes["fps"])) # fix frame values to include handles - asset_attributes.update({ - "frameStart": frame_start - handle_start, - "frameEnd": frame_end + handle_end, - "fps": fps_data - }) - - self.log.debug(pformat( - asset_attributes - )) - - # Get format - _format = root["format"].value() - - # Get values from nukescript - script_attributes = { - "handleStart": int(knob_data["handleStart"]), - "handleEnd": int(knob_data["handleEnd"]), - "fps": float("{0:.4f}".format(root['fps'].value())), - "frameStart": int(root["first_frame"].getValue()), - "frameEnd": int(root["last_frame"].getValue()), - "resolutionWidth": _format.width(), - "resolutionHeight": _format.height(), - "pixelAspect": _format.pixelAspect() - } - self.log.debug(pformat( - script_attributes - )) + asset_attributes["fps"] = float("{0:.4f}".format( + asset_attributes["fps"])) + script_data["fps"] = float("{0:.4f}".format( + script_data["fps"])) # Compare asset's values Nukescript X Database not_matching = [] @@ -86,14 +52,14 @@ class ValidateScriptAttributes(pyblish.api.InstancePlugin): "Asset vs Script attribute \"{}\": {}, {}".format( attr, asset_attributes[attr], - script_attributes[attr] + script_data[attr] ) ) - if asset_attributes[attr] != script_attributes[attr]: + if asset_attributes[attr] != script_data[attr]: not_matching.append({ "name": attr, "expected": asset_attributes[attr], - "actual": script_attributes[attr] + "actual": script_data[attr] }) # Raise error if not matching From bba88cad534b17dab5e111839741c9697198d679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 7 Nov 2022 13:48:25 +0100 Subject: [PATCH 095/211] Update openpype/hosts/nuke/api/pipeline.py Co-authored-by: Milan Kolar --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 0f49419903..4093399435 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -226,7 +226,7 @@ def _install_menu(): menu.addSeparator() menu.addCommand( - "Create... [depricated]", + "Create... [deprecated]", lambda: nuke.message( "New position is in \"Publish...\" and \"Create\" tab") ) From 9b230f615c2a36628fb7460b2a06ad9bf40a835f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 7 Nov 2022 13:48:47 +0100 Subject: [PATCH 096/211] Update openpype/hosts/nuke/api/pipeline.py Co-authored-by: Milan Kolar --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 4093399435..80b13be8f4 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -228,7 +228,7 @@ def _install_menu(): menu.addCommand( "Create... [deprecated]", lambda: nuke.message( - "New position is in \"Publish...\" and \"Create\" tab") + "Creator has been moved, you'll find it in the Publish tool -> Create tab") ) menu.addCommand( "Publish...", From ca050aa9ae5c1b272970dbf6462a05c4f8a36f21 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 7 Nov 2022 14:47:31 +0100 Subject: [PATCH 097/211] shortening line --- openpype/hosts/nuke/api/pipeline.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 80b13be8f4..58cd445388 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -228,7 +228,9 @@ def _install_menu(): menu.addCommand( "Create... [deprecated]", lambda: nuke.message( - "Creator has been moved, you'll find it in the Publish tool -> Create tab") + "Creator has been moved, you'll find it " + "in the Publish tool -> Create tab" + ) ) menu.addCommand( "Publish...", From 33b407be3689244ac1e7d210df50b6987b29b708 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 7 Nov 2022 14:48:37 +0100 Subject: [PATCH 098/211] nuke: removing custom order --- openpype/hosts/nuke/plugins/publish/collect_workfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py index 54c77b1e4e..852042e6e9 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -6,7 +6,7 @@ import pyblish.api class CollectWorkfile(pyblish.api.InstancePlugin): """Collect current script for publish.""" - order = pyblish.api.CollectorOrder - 0.498 + order = pyblish.api.CollectorOrder label = "Collect Workfile" hosts = ['nuke'] families = ["workfile"] From 9cfcea8e1ce74a112b3fd8b04d419d43a26885c2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Nov 2022 18:01:23 +0100 Subject: [PATCH 099/211] nuke: removing version data families > slate --- openpype/hosts/nuke/plugins/publish/collect_slate_node.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index 72b0614d2b..5701087697 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -35,7 +35,6 @@ class CollectSlate(pyblish.api.InstancePlugin): instance.data["slateNode"] = slate_node instance.data["slate"] = True instance.data["families"].append("slate") - instance.data["versionData"]["families"].append("slate") self.log.info( "Slate node is in node graph: `{}`".format(slate.name())) self.log.debug( From 2f50c0261fe7798fad2a04c9e60faac7b847a4e5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Nov 2022 21:42:13 +0100 Subject: [PATCH 100/211] nuke: removing instance only clear instance data knob --- openpype/hosts/nuke/api/pipeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 58cd445388..e739d7335e 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -545,7 +545,8 @@ def remove_instance(instance): instance (dict): instance representation from subsetmanager model """ instance_node = instance.transient_data["node"] - nuke.delete(instance_node) + instance_knob = instance_node.knobs()[INSTANCE_DATA_KNOB] + instance_node.removeKnob(instance_knob) def select_instance(instance): From 0249eee113a282249f678925e80d3bf94238a8ce Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Nov 2022 22:44:46 +0100 Subject: [PATCH 101/211] nuke: workfile instance updating changes --- .../hosts/nuke/plugins/create/workfile_creator.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index 31068c1828..72ef61e63f 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -5,6 +5,10 @@ from openpype.pipeline import ( CreatedInstance, legacy_io, ) +from openpype.hosts.nuke.api import ( + INSTANCE_DATA_KNOB, + set_node_data +) import nuke @@ -50,8 +54,14 @@ class WorkfileCreator(AutoCreator): self._add_instance_to_context(instance) def update_instances(self, update_list): - # nothing to change on workfiles - pass + for created_inst, _changes in update_list: + instance_node = created_inst.transient_data["node"] + + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + created_inst.data_to_store() + ) def create(self, options=None): # no need to create if it is created From b137b547a3b1e7a36cfb22489f2a16b26a31e86c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 18 Nov 2022 13:54:14 +0100 Subject: [PATCH 102/211] nuke: validator with interactive publisher attribute --- .../publish/validate_output_resolution.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py index c581e682a7..70451ebc95 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py +++ b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py @@ -1,12 +1,19 @@ import pyblish.api from openpype.hosts.nuke import api as napi -from openpype.pipeline import PublishXmlValidationError from openpype.pipeline.publish import RepairAction +from openpype.pipeline import ( + PublishXmlValidationError, + OptionalPyblishPluginMixin +) + import nuke -class ValidateOutputResolution(pyblish.api.InstancePlugin): +class ValidateOutputResolution( + OptionalPyblishPluginMixin, + pyblish.api.InstancePlugin +): """Validates Output Resolution. It is making sure the resolution of write's input is the same as @@ -15,7 +22,7 @@ class ValidateOutputResolution(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder optional = True - families = ["render", "render.local", "render.farm"] + families = ["render"] label = "Write Resolution" hosts = ["nuke"] actions = [RepairAction] @@ -24,6 +31,9 @@ class ValidateOutputResolution(pyblish.api.InstancePlugin): resolution_msg = "Reformat is set to wrong format" def process(self, instance): + if not self.is_active(instance.data): + return + invalid = self.get_invalid(instance) if invalid: raise PublishXmlValidationError(self, invalid) From 2b0ed94fa4f565290d7550d08c2972d637862ac7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 18 Nov 2022 16:14:17 +0100 Subject: [PATCH 103/211] nuke: adding interactive publish attribute --- .../plugins/publish/validate_script_attributes.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py index f932ef2c40..bd0bbf8044 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py @@ -1,13 +1,19 @@ from copy import deepcopy import pyblish.api -from openpype.pipeline import PublishXmlValidationError +from openpype.pipeline import ( + PublishXmlValidationError, + OptionalPyblishPluginMixin +) from openpype.pipeline.publish import RepairAction from openpype.hosts.nuke.api.lib import ( WorkfileSettings ) -class ValidateScriptAttributes(pyblish.api.InstancePlugin): +class ValidateScriptAttributes( + OptionalPyblishPluginMixin, + pyblish.api.InstancePlugin +): """ Validates file output. """ order = pyblish.api.ValidatorOrder + 0.1 @@ -18,6 +24,9 @@ class ValidateScriptAttributes(pyblish.api.InstancePlugin): actions = [RepairAction] def process(self, instance): + if not self.is_active(instance.data): + return + script_data = deepcopy(instance.context.data["scriptData"]) asset = instance.data["assetEntity"] From 93543a97367bdbe3c9dc1267bada1945764799c5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 22 Nov 2022 21:37:15 +0100 Subject: [PATCH 104/211] Nuke: create opens to create tab --- openpype/hosts/nuke/api/pipeline.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 85283680bd..6fd4c3651c 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -226,15 +226,16 @@ def _install_menu(): menu.addSeparator() menu.addCommand( - "Create... [deprecated]", - lambda: nuke.message( - "Creator has been moved, you'll find it " - "in the Publish tool -> Create tab" + "Create...", + lambda: host_tools.show_publisher( + tab="create" ) ) menu.addCommand( "Publish...", - host_tools.show_publisher + lambda: host_tools.show_publisher( + tab="publish" + ) ) menu.addCommand( "Load...", From e89cdd0239927c930b6b708bc4128aef85250009 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 10:12:59 +0100 Subject: [PATCH 105/211] Nuke: returning Create shorcut --- openpype/hosts/nuke/api/pipeline.py | 1 + openpype/settings/defaults/project_settings/nuke.json | 1 + 2 files changed, 2 insertions(+) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 6fd4c3651c..268d25b68e 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -343,6 +343,7 @@ def add_shortcuts_from_presets(): if nuke_presets.get("menu"): menu_label_mapping = { + "create": "Create...", "manage": "Manage...", "load": "Load...", "build_workfile": "Build Workfile", diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index a3f97c11c4..5aeca288ad 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -1,6 +1,7 @@ { "general": { "menu": { + "create": "ctrl+alt+c", "publish": "ctrl+alt+p", "load": "ctrl+alt+l", "manage": "ctrl+alt+m", From 3f4be3aa69062820f6f03a2dcb2265c72c123e6d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 10:13:23 +0100 Subject: [PATCH 106/211] Nuke: adding input node type validation --- openpype/hosts/nuke/plugins/create/create_camera.py | 10 ++++++++-- openpype/hosts/nuke/plugins/create/create_model.py | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index ac1a0c7db7..dc4a30f513 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -26,6 +26,10 @@ class CreateCamera(NukeCreator): ): with maintained_selection(): if self.selected_nodes: + node = self.selected_nodes[0] + if node.Class() != "Camera3": + raise NukeCreatorError( + "Creator error: Select only camera node type") created_node = self.selected_nodes[0] else: created_node = nuke.createNode("Camera2") @@ -57,8 +61,10 @@ class CreateCamera(NukeCreator): if pre_create_data.get("use_selection"): self.selected_nodes = nuke.selectedNodes() if self.selected_nodes == []: - raise NukeCreatorError("Creator error: No active selection") + raise NukeCreatorError( + "Creator error: No active selection") elif len(self.selected_nodes) > 1: - NukeCreatorError("Creator error: Select only one camera node") + raise NukeCreatorError( + "Creator error: Select only one camera node") else: self.selected_nodes = [] diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index 22b28cb7ce..f0d0f0918f 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -27,7 +27,11 @@ class CreateModel(NukeCreator): ): with maintained_selection(): if self.selected_nodes: - created_node = self.selected_nodes[0] + node = self.selected_nodes[0] + if node.Class() != "Scene": + raise NukeCreatorError( + "Creator error: Select only 'Scene' node type") + created_node = node else: created_node = nuke.createNode("Scene") From 2413c8ca78b58dfcf5ec0b7bfcdab47f92d1c421 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 10:32:57 +0100 Subject: [PATCH 107/211] nuke: refactor Create Gizmo plugin --- .../hosts/nuke/plugins/create/create_gizmo.py | 134 ++++++++---------- 1 file changed, 58 insertions(+), 76 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_gizmo.py b/openpype/hosts/nuke/plugins/create/create_gizmo.py index d616f6f7ad..1869874e22 100644 --- a/openpype/hosts/nuke/plugins/create/create_gizmo.py +++ b/openpype/hosts/nuke/plugins/create/create_gizmo.py @@ -1,87 +1,69 @@ import nuke - -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - maintained_selection, - select_nodes, - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateGizmo(plugin.OpenPypeCreator): - """Add Publishable "gizmo" group +class CreateGizmo(NukeCreator): + """Add Publishable Group as gizmo""" - The name is symbolically gizmo as presumably - it is something familiar to nuke users as group of nodes - distributed downstream in workflow - """ - - name = "gizmo" - label = "Gizmo" + identifier = "create_gizmo" + label = "Gizmo (group)" family = "gizmo" icon = "file-archive-o" - defaults = ["ViewerInput", "Lut", "Effect"] + default_variants = ["ViewerInput", "Lut", "Effect"] - def __init__(self, *args, **kwargs): - super(CreateGizmo, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0x7533c1ff" - return - - def process(self): - if (self.options or {}).get("useSelection"): - nodes = self.nodes - self.log.info(len(nodes)) - if len(nodes) == 1: - select_nodes(nodes) - node = nodes[-1] - # check if Group node - if node.Class() in "Group": - node["name"].setValue("{}_GZM".format(self.name)) - node["tile_color"].setValue(int(self.node_color, 16)) - return set_avalon_knob_data(node, self.data) - else: - msg = ("Please select a group node " - "you wish to publish as the gizmo") - self.log.error(msg) - nuke.message(msg) - - if len(nodes) >= 2: - select_nodes(nodes) - nuke.makeGroup() - gizmo_node = nuke.selectedNode() - gizmo_node["name"].setValue("{}_GZM".format(self.name)) - gizmo_node["tile_color"].setValue(int(self.node_color, 16)) - - # add sticky node with guide - with gizmo_node: - sticky = nuke.createNode("StickyNote") - sticky["label"].setValue( - "Add following:\n- set Input" - " nodes\n- set one Output1\n" - "- create User knobs on the group") - - # add avalon knobs - return set_avalon_knob_data(gizmo_node, self.data) + # plugin attributes + node_color = "0x7533c1ff" + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + node = self.selected_nodes[0] + if node.Class() != "Group": + raise NukeCreatorError( + "Creator error: Select only 'Group' node type") + created_node = node else: - msg = "Please select nodes you wish to add to the gizmo" - self.log.error(msg) - nuke.message(msg) - return + created_node = nuke.collapseToGroup() + + created_node["tile_color"].setValue( + int(self.node_color, 16)) + + created_node["name"].setValue(node_name) + + self.add_info_knob(created_node) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) + + instance = super(CreateGizmo, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(self.selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one 'Group' node") else: - with maintained_selection(): - gizmo_node = nuke.createNode("Group") - gizmo_node["name"].setValue("{}_GZM".format(self.name)) - gizmo_node["tile_color"].setValue(int(self.node_color, 16)) - - # add sticky node with guide - with gizmo_node: - sticky = nuke.createNode("StickyNote") - sticky["label"].setValue( - "Add following:\n- add Input" - " nodes\n- add one Output1\n" - "- create User knobs on the group") - - # add avalon knobs - return set_avalon_knob_data(gizmo_node, self.data) + self.selected_nodes = [] From 415987ec9b92bf9e679d69d7e78210ea935d957d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 10:33:12 +0100 Subject: [PATCH 108/211] nuke: fix error message --- openpype/hosts/nuke/plugins/create/create_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index f0d0f0918f..53b3a58288 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -64,6 +64,6 @@ class CreateModel(NukeCreator): if self.selected_nodes == []: raise NukeCreatorError("Creator error: No active selection") elif len(self.selected_nodes) > 1: - NukeCreatorError("Creator error: Select only one camera node") + NukeCreatorError("Creator error: Select only one 'Scene' node") else: self.selected_nodes = [] From 86f57b1c910ffc9a3f62d25f782ecd7d602d4da9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 11:39:38 +0100 Subject: [PATCH 109/211] nuke: gizmo flow consistency --- openpype/hosts/nuke/plugins/publish/collect_gizmo.py | 8 ++++---- openpype/hosts/nuke/plugins/publish/extract_gizmo.py | 11 +---------- openpype/hosts/nuke/plugins/publish/validate_gizmo.py | 2 +- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index c194f70f7e..3a877fc194 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -7,18 +7,18 @@ class CollectGizmo(pyblish.api.InstancePlugin): """ order = pyblish.api.CollectorOrder + 0.22 - label = "Collect Gizmo (Group)" + label = "Collect Gizmo (group)" hosts = ["nuke"] families = ["gizmo"] def process(self, instance): - grpn = instance.data["transientData"]["node"] + + gizmo_node = instance.data["transientData"]["node"] # add family to familiess instance.data["families"].insert(0, instance.data["family"]) # make label nicer - instance.data["label"] = "{0} ({1} nodes)".format( - grpn.name(), len(instance) - 1) + instance.data["label"] = gizmo_node.name() # Get frame range handle_start = instance.context.data["handleStart"] diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index 4ca80e9995..b0b1a9f7b7 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -19,7 +19,7 @@ class ExtractGizmo(publish.Extractor): """ order = pyblish.api.ExtractorOrder - label = "Extract Gizmo (Group)" + label = "Extract Gizmo (group)" hosts = ["nuke"] families = ["gizmo"] @@ -55,15 +55,6 @@ class ExtractGizmo(publish.Extractor): # convert gizmos to groups pnutils.bake_gizmos_recursively(copy_grpn) - # remove avalonknobs - knobs = copy_grpn.knobs() - avalon_knobs = [k for k in knobs.keys() - for ak in ["avalon:", "ak:"] - if ak in k] - avalon_knobs.append("publish") - for ak in avalon_knobs: - copy_grpn.removeKnob(knobs[ak]) - # add to temporary nodes tmp_nodes.append(copy_grpn) diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 8e844247ee..878d938bea 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -39,7 +39,7 @@ class ValidateGizmo(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder optional = True families = ["gizmo"] - label = "Validate Gizmo (Group)" + label = "Validate Gizmo (group)" hosts = ["nuke"] actions = [OpenFailedGroupNode] From 49b7e58adcf0fa206e67acccfb811a9a1e068320 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 11:40:15 +0100 Subject: [PATCH 110/211] nuke: fixing output node exctractor for Root exception --- openpype/hosts/nuke/plugins/publish/extract_ouput_node.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py index 6067e6cf6b..e66cfd9018 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py +++ b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py @@ -21,11 +21,12 @@ class CreateOutputNode(pyblish.api.ContextPlugin): inst.data.get("transientData", {}).get("node") for inst in context if inst.data.get("transientData", {}).get("node") + if inst.data.get( + "transientData", {}).get("node").Class() != "Root" ] if active_node: - self.log.info(active_node) - active_node = active_node[0] + active_node = active_node.pop() self.log.info(active_node) active_node['selected'].setValue(True) From e026a27b9380467eed8ae2d2ecc082394f77cc2d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 12:11:33 +0100 Subject: [PATCH 111/211] hiero: fixing thumbnail if multillayer exr --- openpype/hosts/hiero/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/hiero/plugins/publish/extract_thumbnail.py b/openpype/hosts/hiero/plugins/publish/extract_thumbnail.py index e64aa89b26..5ca79dc1dc 100644 --- a/openpype/hosts/hiero/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/hiero/plugins/publish/extract_thumbnail.py @@ -41,7 +41,7 @@ class ExtractThumnail(publish.Extractor): track_item_name, thumb_frame, ".png") thumb_path = os.path.join(staging_dir, thumb_file) - thumbnail = track_item.thumbnail(thumb_frame).save( + thumbnail = track_item.thumbnail(thumb_frame, "colour").save( thumb_path, format='png' ) From 9f61aa338536321b17730b175a8b603b0870a385 Mon Sep 17 00:00:00 2001 From: Joseff Date: Mon, 12 Dec 2022 14:27:26 +0100 Subject: [PATCH 112/211] Refactorization of folder coloring --- .../UE_4.7/Config/DefaultOpenPypeSettings.ini | 2 + .../UE_4.7/Source/OpenPype/OpenPype.Build.cs | 1 + .../Source/OpenPype/Private/OpenPype.cpp | 64 +++++++++++++++-- .../Source/OpenPype/Private/OpenPypeLib.cpp | 24 ++++--- .../Private/OpenPypePublishInstance.cpp | 51 +++++++++++++- .../OpenPype/Private/OpenPypeSettings.cpp | 21 ++++++ .../UE_4.7/Source/OpenPype/Public/OpenPype.h | 3 +- .../Source/OpenPype/Public/OpenPypeLib.h | 4 +- .../OpenPype/Public/OpenPypePublishInstance.h | 18 +++-- .../Source/OpenPype/Public/OpenPypeSettings.h | 32 +++++++++ .../UE_5.0/Config/DefaultOpenPypeSettings.ini | 2 + .../UE_5.0/Source/OpenPype/OpenPype.Build.cs | 1 + .../Source/OpenPype/Private/OpenPype.cpp | 69 +++++++++++++++++-- .../Source/OpenPype/Private/OpenPypeLib.cpp | 24 ++++--- .../Private/OpenPypePublishInstance.cpp | 69 ++++++++++++++++--- .../OpenPype/Private/OpenPypeSettings.cpp | 21 ++++++ .../UE_5.0/Source/OpenPype/Public/OpenPype.h | 2 + .../Source/OpenPype/Public/OpenPypeLib.h | 4 +- .../OpenPype/Public/OpenPypePublishInstance.h | 23 ++++--- .../Source/OpenPype/Public/OpenPypeSettings.h | 32 +++++++++ 20 files changed, 401 insertions(+), 66 deletions(-) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini b/openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini new file mode 100644 index 0000000000..8a883cf1db --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini @@ -0,0 +1,2 @@ +[/Script/OpenPype.OpenPypeSettings] +FolderColor=(R=91,G=197,B=220,A=255) \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs index c30835b63d..46e5dcb2df 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs @@ -42,6 +42,7 @@ public class OpenPype : ModuleRules "Engine", "Slate", "SlateCore", + "AssetTools" // ... add private dependencies that you statically link with here ... } ); diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp index 15c46b3862..d20abec9b1 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp @@ -1,6 +1,11 @@ #include "OpenPype.h" + +#include "ISettingsContainer.h" +#include "ISettingsModule.h" +#include "ISettingsSection.h" #include "LevelEditor.h" #include "OpenPypePythonBridge.h" +#include "OpenPypeSettings.h" #include "OpenPypeStyle.h" @@ -11,13 +16,12 @@ static const FName OpenPypeTabName("OpenPype"); // This function is triggered when the plugin is staring up void FOpenPypeModule::StartupModule() { - FOpenPypeStyle::Initialize(); FOpenPypeStyle::SetIcon("Logo", "openpype40"); // Create the Extender that will add content to the menu FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); - + TSharedPtr MenuExtender = MakeShareable(new FExtender()); TSharedPtr ToolbarExtender = MakeShareable(new FExtender()); @@ -37,6 +41,7 @@ void FOpenPypeModule::StartupModule() LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); + RegisterSettings(); } void FOpenPypeModule::ShutdownModule() @@ -64,7 +69,6 @@ void FOpenPypeModule::AddMenuEntry(FMenuBuilder& MenuBuilder) FSlateIcon(FOpenPypeStyle::GetStyleSetName(), "OpenPype.Logo"), FUIAction(FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuDialog)) ); - } MenuBuilder.EndSection(); } @@ -89,13 +93,63 @@ void FOpenPypeModule::AddToobarEntry(FToolBarBuilder& ToolbarBuilder) ToolbarBuilder.EndSection(); } +void FOpenPypeModule::RegisterSettings() +{ + ISettingsModule& SettingsModule = FModuleManager::LoadModuleChecked("Settings"); -void FOpenPypeModule::MenuPopup() { + // Create the new category + // TODO: After the movement of the plugin from the game to editor, it might be necessary to move this! + ISettingsContainerPtr SettingsContainer = SettingsModule.GetContainer("Project"); + + SettingsContainer->DescribeCategory("OpenPypeSettings", + LOCTEXT("RuntimeWDCategoryName", "OpenPypeSettings"), + LOCTEXT("RuntimeWDCategoryDescription", + "Configuration for the Open pype module")); + + UOpenPypeSettings* Settings = GetMutableDefault(); + + // Register the settings + ISettingsSectionPtr SettingsSection = SettingsModule.RegisterSettings("Project", "OpenPype", "General", + LOCTEXT("RuntimeGeneralSettingsName", + "General"), + LOCTEXT("RuntimeGeneralSettingsDescription", + "Base configuration for Open Pype Module"), + Settings + ); + + // Register the save handler to your settings, you might want to use it to + // validate those or just act to settings changes. + if (SettingsSection.IsValid()) + { + SettingsSection->OnModified().BindRaw(this, &FOpenPypeModule::HandleSettingsSaved); + } +} + +bool FOpenPypeModule::HandleSettingsSaved() +{ + UOpenPypeSettings* Settings = GetMutableDefault(); + bool ResaveSettings = false; + + // You can put any validation code in here and resave the settings in case an invalid + // value has been entered + + if (ResaveSettings) + { + Settings->SaveConfig(); + } + + return true; +} + + +void FOpenPypeModule::MenuPopup() +{ UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); bridge->RunInPython_Popup(); } -void FOpenPypeModule::MenuDialog() { +void FOpenPypeModule::MenuDialog() +{ UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); bridge->RunInPython_Dialog(); } diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp index 5facab7b8b..a58e921288 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp @@ -1,4 +1,6 @@ #include "OpenPypeLib.h" + +#include "AssetViewUtils.h" #include "Misc/Paths.h" #include "Misc/ConfigCacheIni.h" #include "UObject/UnrealType.h" @@ -10,21 +12,23 @@ * @warning This color will appear only after Editor restart. Is there a better way? */ -void UOpenPypeLib::CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd) +bool UOpenPypeLib::SetFolderColor(const FString& FolderPath, const FLinearColor& FolderColor, const bool& bForceAdd) { - auto SaveColorInternal = [](FString InPath, FLinearColor InFolderColor) + if (AssetViewUtils::DoesFolderExist(FolderPath)) { - // Saves the color of the folder to the config - if (FPaths::FileExists(GEditorPerProjectIni)) - { - GConfig->SetString(TEXT("PathColor"), *InPath, *InFolderColor.ToString(), GEditorPerProjectIni); - } + const TSharedPtr LinearColor = MakeShared(FolderColor); - }; - - SaveColorInternal(FolderPath, FolderColor); + AssetViewUtils::SaveColor(FolderPath, LinearColor, true); + UE_LOG(LogAssetData, Display, TEXT("A color {%s} has been set to folder \"%s\""), *LinearColor->ToString(), + *FolderPath) + return true; + } + UE_LOG(LogAssetData, Display, TEXT("Setting a color {%s} to folder \"%s\" has failed! Directory doesn't exist!"), + *FolderColor.ToString(), *FolderPath) + return false; } + /** * Returns all poperties on given object * @param cls - class diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp index ed81104c05..38740f1cbd 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp @@ -3,6 +3,8 @@ #include "OpenPypePublishInstance.h" #include "AssetRegistryModule.h" #include "NotificationManager.h" +#include "OpenPypeLib.h" +#include "OpenPypeSettings.h" #include "SNotificationList.h" //Moves all the invalid pointers to the end to prepare them for the shrinking @@ -36,6 +38,11 @@ UOpenPypePublishInstance::UOpenPypePublishInstance(const FObjectInitializer& Obj AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UOpenPypePublishInstance::OnAssetCreated); AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UOpenPypePublishInstance::OnAssetRemoved); AssetRegistryModule.Get().OnAssetUpdated().AddUObject(this, &UOpenPypePublishInstance::OnAssetUpdated); + +#ifdef WITH_EDITOR + ColorOpenPypeDirs(); +#endif + } void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) @@ -58,7 +65,7 @@ void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) if (AssetDataInternal.Emplace(Asset).IsValidId()) { UE_LOG(LogTemp, Log, TEXT("Added an Asset to PublishInstance - Publish Instance: %s, Asset %s"), - *this->GetName(), *Asset->GetName()); + *this->GetName(), *Asset->GetName()); } } } @@ -96,6 +103,48 @@ bool UOpenPypePublishInstance::IsUnderSameDir(const UObject* InAsset) const #ifdef WITH_EDITOR +void UOpenPypePublishInstance::ColorOpenPypeDirs() +{ + FString PathName = this->GetPathName(); + + //Check whether the path contains the defined OpenPype folder + if (!PathName.Contains(TEXT("OpenPype"))) return; + + //Get the base path for open pype + FString PathLeft, PathRight; + PathName.Split(FString("OpenPype"), &PathLeft, &PathRight); + + if (PathLeft.IsEmpty() || PathRight.IsEmpty()) + { + UE_LOG(LogAssetData, Error, TEXT("Failed to retrieve the base OpenPype directory!")) + return; + } + + PathName.RemoveFromEnd(PathRight, ESearchCase::CaseSensitive); + + //Get the current settings + const UOpenPypeSettings* Settings = GetMutableDefault(); + + //Color the base folder + UOpenPypeLib::SetFolderColor(PathName, Settings->GetFolderFColor(), false); + + //Get Sub paths, iterate through them and color them according to the folder color in UOpenPypeSettings + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked( + "AssetRegistry"); + + TArray PathList; + + AssetRegistryModule.Get().GetSubPaths(PathName, PathList, true); + + if (PathList.Num() > 0) + { + for (const FString& Path : PathList) + { + UOpenPypeLib::SetFolderColor(Path, Settings->GetFolderFColor(), false); + } + } +} + void UOpenPypePublishInstance::SendNotification(const FString& Text) const { FNotificationInfo Info{FText::FromString(Text)}; diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp new file mode 100644 index 0000000000..7134614d22 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp @@ -0,0 +1,21 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "OpenPypeSettings.h" + +#include "IPluginManager.h" +#include "UObjectGlobals.h" + +/** + * Mainly is used for initializing default values if the DefaultOpenPypeSettings.ini file does not exist in the saved config + */ +UOpenPypeSettings::UOpenPypeSettings(const FObjectInitializer& ObjectInitializer) +{ + + const FString ConfigFilePath = OPENPYPE_SETTINGS_FILEPATH; + + // This has to be probably in the future set using the UE Reflection system + FColor Color; + GConfig->GetColor(TEXT("/Script/OpenPype.OpenPypeSettings"), TEXT("FolderColor"), Color, ConfigFilePath); + + FolderColor = Color; +} \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h index db3f299354..9cfa60176c 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h @@ -12,10 +12,11 @@ public: virtual void ShutdownModule() override; private: + void RegisterSettings(); + bool HandleSettingsSaved(); void AddMenuEntry(FMenuBuilder& MenuBuilder); void AddToobarEntry(FToolBarBuilder& ToolbarBuilder); void MenuPopup(); void MenuDialog(); - }; diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h index 59e9c8bd76..06425c7c7d 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h @@ -5,14 +5,14 @@ UCLASS(Blueprintable) -class OPENPYPE_API UOpenPypeLib : public UObject +class OPENPYPE_API UOpenPypeLib : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = Python) - static void CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd); + static bool SetFolderColor(const FString& FolderPath, const FLinearColor& FolderColor,const bool& bForceAdd); UFUNCTION(BlueprintCallable, Category = Python) static TArray GetAllProperties(UClass* cls); diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h index 0e946fb039..cd414fe2cc 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h @@ -8,10 +8,8 @@ UCLASS(Blueprintable) class OPENPYPE_API UOpenPypePublishInstance : public UPrimaryDataAsset { GENERATED_UCLASS_BODY() - + public: - - /** /** * Retrieves all the assets which are monitored by the Publish Instance (Monitors assets in the directory which is * placed in) @@ -58,8 +56,10 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure) TSet GetAllAssets() const { - const TSet>& IteratedSet = bAddExternalAssets ? AssetDataInternal.Union(AssetDataExternal) : AssetDataInternal; - + const TSet>& IteratedSet = bAddExternalAssets + ? AssetDataInternal.Union(AssetDataExternal) + : AssetDataInternal; + //Create a new TSet only with raw pointers. TSet ResultSet; @@ -69,12 +69,10 @@ public: return ResultSet; } - private: - UPROPERTY(VisibleAnywhere, Category="Assets") TSet> AssetDataInternal; - + /** * This property allows exposing the array to include other assets from any other directory than what it's currently * monitoring. NOTE: that these assets have to be added manually! They are not automatically registered or added! @@ -93,11 +91,11 @@ private: bool IsUnderSameDir(const UObject* InAsset) const; #ifdef WITH_EDITOR + + void ColorOpenPypeDirs(); void SendNotification(const FString& Text) const; virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; #endif - }; - diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h new file mode 100644 index 0000000000..2df6c887cf --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Object.h" +#include "OpenPypeSettings.generated.h" + +#define OPENPYPE_SETTINGS_FILEPATH IPluginManager::Get().FindPlugin("OpenPype")->GetBaseDir() / TEXT("Config") / TEXT("DefaultOpenPypeSettings.ini") + +UCLASS(Config=OpenPypeSettings, DefaultConfig) +class OPENPYPE_API UOpenPypeSettings : public UObject +{ + GENERATED_UCLASS_BODY() + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Settings) + FColor GetFolderFColor() const + { + return FolderColor; + } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Settings) + FLinearColor GetFolderFLinearColor() const + { + return FLinearColor(FolderColor); + } + +protected: + + UPROPERTY(config, EditAnywhere, Category = Folders) + FColor FolderColor = FColor(25,45,223); +}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini b/openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini new file mode 100644 index 0000000000..8a883cf1db --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini @@ -0,0 +1,2 @@ +[/Script/OpenPype.OpenPypeSettings] +FolderColor=(R=91,G=197,B=220,A=255) \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs index fcfd268234..2ee5d9027c 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs @@ -44,6 +44,7 @@ public class OpenPype : ModuleRules "Engine", "Slate", "SlateCore", + "AssetTools" // ... add private dependencies that you statically link with here ... } ); diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp index b3bd9a81b3..11aae0ffc2 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp @@ -1,8 +1,12 @@ #include "OpenPype.h" + +#include "ISettingsContainer.h" +#include "ISettingsModule.h" +#include "ISettingsSection.h" #include "OpenPypeStyle.h" #include "OpenPypeCommands.h" #include "OpenPypePythonBridge.h" -#include "LevelEditor.h" +#include "OpenPypeSettings.h" #include "Misc/MessageDialog.h" #include "ToolMenus.h" @@ -29,7 +33,10 @@ void FOpenPypeModule::StartupModule() FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuDialog), FCanExecuteAction()); - UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FOpenPypeModule::RegisterMenus)); + UToolMenus::RegisterStartupCallback( + FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FOpenPypeModule::RegisterMenus)); + + RegisterSettings(); } void FOpenPypeModule::ShutdownModule() @@ -43,6 +50,55 @@ void FOpenPypeModule::ShutdownModule() FOpenPypeCommands::Unregister(); } + +void FOpenPypeModule::RegisterSettings() +{ + ISettingsModule& SettingsModule = FModuleManager::LoadModuleChecked("Settings"); + + // Create the new category + // TODO: After the movement of the plugin from the game to editor, it might be necessary to move this! + ISettingsContainerPtr SettingsContainer = SettingsModule.GetContainer("Project"); + + SettingsContainer->DescribeCategory("OpenPypeSettings", + LOCTEXT("RuntimeWDCategoryName", "OpenPypeSettings"), + LOCTEXT("RuntimeWDCategoryDescription", + "Configuration for the Open pype module")); + + UOpenPypeSettings* Settings = GetMutableDefault(); + + // Register the settings + ISettingsSectionPtr SettingsSection = SettingsModule.RegisterSettings("Project", "OpenPype", "General", + LOCTEXT("RuntimeGeneralSettingsName", + "General"), + LOCTEXT("RuntimeGeneralSettingsDescription", + "Base configuration for Open Pype Module"), + Settings + ); + + // Register the save handler to your settings, you might want to use it to + // validate those or just act to settings changes. + if (SettingsSection.IsValid()) + { + SettingsSection->OnModified().BindRaw(this, &FOpenPypeModule::HandleSettingsSaved); + } +} + +bool FOpenPypeModule::HandleSettingsSaved() +{ + UOpenPypeSettings* Settings = GetMutableDefault(); + bool ResaveSettings = false; + + // You can put any validation code in here and resave the settings in case an invalid + // value has been entered + + if (ResaveSettings) + { + Settings->SaveConfig(); + } + + return true; +} + void FOpenPypeModule::RegisterMenus() { // Owner will be used for cleanup in call to UToolMenus::UnregisterOwner @@ -64,7 +120,8 @@ void FOpenPypeModule::RegisterMenus() { FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("PluginTools"); { - FToolMenuEntry& Entry = Section.AddEntry(FToolMenuEntry::InitToolBarButton(FOpenPypeCommands::Get().OpenPypeTools)); + FToolMenuEntry& Entry = Section.AddEntry( + FToolMenuEntry::InitToolBarButton(FOpenPypeCommands::Get().OpenPypeTools)); Entry.SetCommandList(PluginCommands); } } @@ -72,12 +129,14 @@ void FOpenPypeModule::RegisterMenus() } -void FOpenPypeModule::MenuPopup() { +void FOpenPypeModule::MenuPopup() +{ UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); bridge->RunInPython_Popup(); } -void FOpenPypeModule::MenuDialog() { +void FOpenPypeModule::MenuDialog() +{ UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); bridge->RunInPython_Dialog(); } diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp index 5facab7b8b..a58e921288 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp @@ -1,4 +1,6 @@ #include "OpenPypeLib.h" + +#include "AssetViewUtils.h" #include "Misc/Paths.h" #include "Misc/ConfigCacheIni.h" #include "UObject/UnrealType.h" @@ -10,21 +12,23 @@ * @warning This color will appear only after Editor restart. Is there a better way? */ -void UOpenPypeLib::CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd) +bool UOpenPypeLib::SetFolderColor(const FString& FolderPath, const FLinearColor& FolderColor, const bool& bForceAdd) { - auto SaveColorInternal = [](FString InPath, FLinearColor InFolderColor) + if (AssetViewUtils::DoesFolderExist(FolderPath)) { - // Saves the color of the folder to the config - if (FPaths::FileExists(GEditorPerProjectIni)) - { - GConfig->SetString(TEXT("PathColor"), *InPath, *InFolderColor.ToString(), GEditorPerProjectIni); - } + const TSharedPtr LinearColor = MakeShared(FolderColor); - }; - - SaveColorInternal(FolderPath, FolderColor); + AssetViewUtils::SaveColor(FolderPath, LinearColor, true); + UE_LOG(LogAssetData, Display, TEXT("A color {%s} has been set to folder \"%s\""), *LinearColor->ToString(), + *FolderPath) + return true; + } + UE_LOG(LogAssetData, Display, TEXT("Setting a color {%s} to folder \"%s\" has failed! Directory doesn't exist!"), + *FolderColor.ToString(), *FolderPath) + return false; } + /** * Returns all poperties on given object * @param cls - class diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp index 322663eeec..6f41600bae 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp @@ -2,8 +2,9 @@ #include "OpenPypePublishInstance.h" #include "AssetRegistryModule.h" -#include "AssetToolsModule.h" -#include "Framework/Notifications/NotificationManager.h" +#include "NotificationManager.h" +#include "OpenPypeLib.h" +#include "OpenPypeSettings.h" #include "SNotificationList.h" //Moves all the invalid pointers to the end to prepare them for the shrinking @@ -16,8 +17,11 @@ UOpenPypePublishInstance::UOpenPypePublishInstance(const FObjectInitializer& Obj const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked< FAssetRegistryModule>("AssetRegistry"); + const FPropertyEditorModule& PropertyEditorModule = FModuleManager::LoadModuleChecked( + "PropertyEditor"); + FString Left, Right; - GetPathName().Split(GetName(), &Left, &Right); + GetPathName().Split("/" + GetName(), &Left, &Right); FARFilter Filter; Filter.PackagePaths.Emplace(FName(Left)); @@ -34,15 +38,17 @@ UOpenPypePublishInstance::UOpenPypePublishInstance(const FObjectInitializer& Obj AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UOpenPypePublishInstance::OnAssetCreated); AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UOpenPypePublishInstance::OnAssetRemoved); AssetRegistryModule.Get().OnAssetUpdated().AddUObject(this, &UOpenPypePublishInstance::OnAssetUpdated); - - + +#ifdef WITH_EDITOR + ColorOpenPypeDirs(); +#endif } void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) { TArray split; - const TObjectPtr Asset = InAssetData.GetAsset(); + UObject* Asset = InAssetData.GetAsset(); if (!IsValid(Asset)) { @@ -58,7 +64,7 @@ void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) if (AssetDataInternal.Emplace(Asset).IsValidId()) { UE_LOG(LogTemp, Log, TEXT("Added an Asset to PublishInstance - Publish Instance: %s, Asset %s"), - *this->GetName(), *Asset->GetName()); + *this->GetName(), *Asset->GetName()); } } } @@ -86,7 +92,7 @@ void UOpenPypePublishInstance::OnAssetUpdated(const FAssetData& InAssetData) REMOVE_INVALID_ENTRIES(AssetDataExternal); } -bool UOpenPypePublishInstance::IsUnderSameDir(const TObjectPtr& InAsset) const +bool UOpenPypePublishInstance::IsUnderSameDir(const UObject* InAsset) const { FString ThisLeft, ThisRight; this->GetPathName().Split(this->GetName(), &ThisLeft, &ThisRight); @@ -96,6 +102,48 @@ bool UOpenPypePublishInstance::IsUnderSameDir(const TObjectPtr& InAsset #ifdef WITH_EDITOR +void UOpenPypePublishInstance::ColorOpenPypeDirs() +{ + FString PathName = this->GetPathName(); + + //Check whether the path contains the defined OpenPype folder + if (!PathName.Contains(TEXT("OpenPype"))) return; + + //Get the base path for open pype + FString PathLeft, PathRight; + PathName.Split(FString("OpenPype"), &PathLeft, &PathRight); + + if (PathLeft.IsEmpty() || PathRight.IsEmpty()) + { + UE_LOG(LogAssetData, Error, TEXT("Failed to retrieve the base OpenPype directory!")) + return; + } + + PathName.RemoveFromEnd(PathRight, ESearchCase::CaseSensitive); + + //Get the current settings + const UOpenPypeSettings* Settings = GetMutableDefault(); + + //Color the base folder + UOpenPypeLib::SetFolderColor(PathName, Settings->GetFolderFColor(), false); + + //Get Sub paths, iterate through them and color them according to the folder color in UOpenPypeSettings + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked( + "AssetRegistry"); + + TArray PathList; + + AssetRegistryModule.Get().GetSubPaths(PathName, PathList, true); + + if (PathList.Num() > 0) + { + for (const FString& Path : PathList) + { + UOpenPypeLib::SetFolderColor(Path, Settings->GetFolderFColor(), false); + } + } +} + void UOpenPypePublishInstance::SendNotification(const FString& Text) const { FNotificationInfo Info{FText::FromString(Text)}; @@ -125,16 +173,15 @@ void UOpenPypePublishInstance::PostEditChangeProperty(FPropertyChangedEvent& Pro PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED( UOpenPypePublishInstance, AssetDataExternal)) { - // Check for duplicated assets for (const auto& Asset : AssetDataInternal) { if (AssetDataExternal.Contains(Asset)) { AssetDataExternal.Remove(Asset); - return SendNotification("You are not allowed to add assets into AssetDataExternal which are already included in AssetDataInternal!"); + return SendNotification( + "You are not allowed to add assets into AssetDataExternal which are already included in AssetDataInternal!"); } - } // Check if no UOpenPypePublishInstance type assets are included diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp new file mode 100644 index 0000000000..7134614d22 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp @@ -0,0 +1,21 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "OpenPypeSettings.h" + +#include "IPluginManager.h" +#include "UObjectGlobals.h" + +/** + * Mainly is used for initializing default values if the DefaultOpenPypeSettings.ini file does not exist in the saved config + */ +UOpenPypeSettings::UOpenPypeSettings(const FObjectInitializer& ObjectInitializer) +{ + + const FString ConfigFilePath = OPENPYPE_SETTINGS_FILEPATH; + + // This has to be probably in the future set using the UE Reflection system + FColor Color; + GConfig->GetColor(TEXT("/Script/OpenPype.OpenPypeSettings"), TEXT("FolderColor"), Color, ConfigFilePath); + + FolderColor = Color; +} \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h index 3ee5eaa65f..4261476da8 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h @@ -14,6 +14,8 @@ public: private: void RegisterMenus(); + void RegisterSettings(); + bool HandleSettingsSaved(); void MenuPopup(); void MenuDialog(); diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h index 59e9c8bd76..06425c7c7d 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h @@ -5,14 +5,14 @@ UCLASS(Blueprintable) -class OPENPYPE_API UOpenPypeLib : public UObject +class OPENPYPE_API UOpenPypeLib : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = Python) - static void CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd); + static bool SetFolderColor(const FString& FolderPath, const FLinearColor& FolderColor,const bool& bForceAdd); UFUNCTION(BlueprintCallable, Category = Python) static TArray GetAllProperties(UClass* cls); diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h index 2f066bd94b..146025bd6d 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h @@ -1,6 +1,5 @@ #pragma once -#include "EditorTutorial.h" #include "Engine.h" #include "OpenPypePublishInstance.generated.h" @@ -9,7 +8,9 @@ UCLASS(Blueprintable) class OPENPYPE_API UOpenPypePublishInstance : public UPrimaryDataAsset { GENERATED_UCLASS_BODY() + public: + /** /** * Retrieves all the assets which are monitored by the Publish Instance (Monitors assets in the directory which is * placed in) @@ -56,8 +57,10 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure) TSet GetAllAssets() const { - const TSet>& IteratedSet = bAddExternalAssets ? AssetDataInternal.Union(AssetDataExternal) : AssetDataInternal; - + const TSet>& IteratedSet = bAddExternalAssets + ? AssetDataInternal.Union(AssetDataExternal) + : AssetDataInternal; + //Create a new TSet only with raw pointers. TSet ResultSet; @@ -72,24 +75,26 @@ private: TSet> AssetDataInternal; /** - * This property allows the instance to include other assets from any other directory than what it's currently - * monitoring. - * @attention assets have to be added manually! They are not automatically registered or added! + * This property allows exposing the array to include other assets from any other directory than what it's currently + * monitoring. NOTE: that these assets have to be added manually! They are not automatically registered or added! */ - UPROPERTY(EditAnywhere, Category="Assets") + UPROPERTY(EditAnywhere, Category = "Assets") bool bAddExternalAssets = false; - UPROPERTY(EditAnywhere, Category="Assets", meta=(EditCondition="bAddExternalAssets")) + UPROPERTY(EditAnywhere, meta=(EditCondition="bAddExternalAssets"), Category="Assets") TSet> AssetDataExternal; + void OnAssetCreated(const FAssetData& InAssetData); void OnAssetRemoved(const FAssetData& InAssetData); void OnAssetUpdated(const FAssetData& InAssetData); - bool IsUnderSameDir(const TObjectPtr& InAsset) const; + bool IsUnderSameDir(const UObject* InAsset) const; #ifdef WITH_EDITOR + void ColorOpenPypeDirs(); + void SendNotification(const FString& Text) const; virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h new file mode 100644 index 0000000000..2df6c887cf --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Object.h" +#include "OpenPypeSettings.generated.h" + +#define OPENPYPE_SETTINGS_FILEPATH IPluginManager::Get().FindPlugin("OpenPype")->GetBaseDir() / TEXT("Config") / TEXT("DefaultOpenPypeSettings.ini") + +UCLASS(Config=OpenPypeSettings, DefaultConfig) +class OPENPYPE_API UOpenPypeSettings : public UObject +{ + GENERATED_UCLASS_BODY() + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Settings) + FColor GetFolderFColor() const + { + return FolderColor; + } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Settings) + FLinearColor GetFolderFLinearColor() const + { + return FLinearColor(FolderColor); + } + +protected: + + UPROPERTY(config, EditAnywhere, Category = Folders) + FColor FolderColor = FColor(25,45,223); +}; \ No newline at end of file From fefb64ed4268db7ef278fb8ad61baf8b544a31d4 Mon Sep 17 00:00:00 2001 From: Joseff Date: Mon, 12 Dec 2022 16:47:12 +0100 Subject: [PATCH 113/211] Removed the unnecessary DescribeCategory() --- .../integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp | 5 ----- .../integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp | 5 ----- 2 files changed, 10 deletions(-) diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp index d20abec9b1..d06a08eb43 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp @@ -101,11 +101,6 @@ void FOpenPypeModule::RegisterSettings() // TODO: After the movement of the plugin from the game to editor, it might be necessary to move this! ISettingsContainerPtr SettingsContainer = SettingsModule.GetContainer("Project"); - SettingsContainer->DescribeCategory("OpenPypeSettings", - LOCTEXT("RuntimeWDCategoryName", "OpenPypeSettings"), - LOCTEXT("RuntimeWDCategoryDescription", - "Configuration for the Open pype module")); - UOpenPypeSettings* Settings = GetMutableDefault(); // Register the settings diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp index 11aae0ffc2..d23de61102 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp @@ -59,11 +59,6 @@ void FOpenPypeModule::RegisterSettings() // TODO: After the movement of the plugin from the game to editor, it might be necessary to move this! ISettingsContainerPtr SettingsContainer = SettingsModule.GetContainer("Project"); - SettingsContainer->DescribeCategory("OpenPypeSettings", - LOCTEXT("RuntimeWDCategoryName", "OpenPypeSettings"), - LOCTEXT("RuntimeWDCategoryDescription", - "Configuration for the Open pype module")); - UOpenPypeSettings* Settings = GetMutableDefault(); // Register the settings From c85594c324e83bf1a8a95ee11f1caaed7c82f1d3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 13 Dec 2022 15:06:40 +0100 Subject: [PATCH 114/211] OP-4512 - fix normalize local name 'local' should be returned for local site only --- openpype/modules/sync_server/providers/local_drive.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/modules/sync_server/providers/local_drive.py b/openpype/modules/sync_server/providers/local_drive.py index 8f55dc529b..98bdb487da 100644 --- a/openpype/modules/sync_server/providers/local_drive.py +++ b/openpype/modules/sync_server/providers/local_drive.py @@ -5,6 +5,7 @@ import threading import time from openpype.lib import Logger +from openpype.lib.local_settings import get_local_site_id from openpype.pipeline import Anatomy from .abstract_provider import AbstractProvider @@ -220,6 +221,6 @@ class LocalDriveHandler(AbstractProvider): def _normalize_site_name(self, site_name): """Transform user id to 'local' for Local settings""" - if site_name != 'studio': + if site_name == get_local_site_id(): return 'local' return site_name From d931198797a02d908803f92f53b6d1632e153b68 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 13 Dec 2022 23:28:15 +0800 Subject: [PATCH 115/211] bug fix image plane load error --- .../maya/plugins/load/load_image_plane.py | 59 +++++++++++-------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index b267921bdc..82c2676982 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -23,8 +23,8 @@ class CameraWindow(QtWidgets.QDialog): self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint) self.camera = None - self.static_image_plane = False - self.show_in_all_views = False + # self.static_image_plane = False + # self.show_in_all_views = False self.widgets = { "label": QtWidgets.QLabel("Select camera for image plane."), @@ -45,8 +45,8 @@ class CameraWindow(QtWidgets.QDialog): for camera in cameras: self.widgets["list"].addItem(camera) - self.widgets["staticImagePlane"].setText("Make Image Plane Static") - self.widgets["showInAllViews"].setText("Show Image Plane in All Views") + # self.widgets["staticImagePlane"].setText("Make Image Plane Static") + # self.widgets["showInAllViews"].setText("Show Image Plane in All Views") # Build buttons. layout = QtWidgets.QHBoxLayout(self.widgets["buttons"]) @@ -57,13 +57,13 @@ class CameraWindow(QtWidgets.QDialog): layout = QtWidgets.QVBoxLayout(self) layout.addWidget(self.widgets["label"]) layout.addWidget(self.widgets["list"]) - layout.addWidget(self.widgets["staticImagePlane"]) - layout.addWidget(self.widgets["showInAllViews"]) + # layout.addWidget(self.widgets["staticImagePlane"]) + # layout.addWidget(self.widgets["showInAllViews"]) layout.addWidget(self.widgets["buttons"]) layout.addWidget(self.widgets["warning"]) self.widgets["okButton"].pressed.connect(self.on_ok_pressed) - self.widgets["cancelButton"].pressed.connect(self.on_cancel_pressed) + self.widgets["cancelButton"].clicked.connect(self.on_cancel_pressed) self.widgets["list"].itemPressed.connect(self.on_list_itemPressed) def on_list_itemPressed(self, item): @@ -73,8 +73,8 @@ class CameraWindow(QtWidgets.QDialog): if self.camera is None: self.widgets["warning"].setVisible(True) return - self.show_in_all_views = self.widgets["showInAllViews"].isChecked() - self.static_image_plane = self.widgets["staticImagePlane"].isChecked() + # self.show_in_all_views = self.widgets["showInAllViews"].isChecked() + # self.static_image_plane = self.widgets["staticImagePlane"].isChecked() self.close() @@ -106,12 +106,12 @@ class ImagePlaneLoader(load.LoaderPlugin): # Get camera from user selection. camera = None - is_static_image_plane = None - is_in_all_views = None + # is_static_image_plane = None + # is_in_all_views = None if data: camera = pm.PyNode(data.get("camera")) - is_static_image_plane = data.get("static_image_plane") - is_in_all_views = data.get("in_all_views") + # is_static_image_plane = data.get("static_image_plane") + # is_in_all_views = data.get("in_all_views") if not camera: cameras = pm.ls(type="camera") @@ -121,8 +121,8 @@ class ImagePlaneLoader(load.LoaderPlugin): window.exec_() camera = camera_names[window.camera] - is_static_image_plane = window.static_image_plane - is_in_all_views = window.show_in_all_views + # is_static_image_plane = window.static_image_plane + # is_in_all_views = window.show_in_all_views if camera == "create_camera": camera = pm.createNode("camera") @@ -139,18 +139,20 @@ class ImagePlaneLoader(load.LoaderPlugin): # Create image plane image_plane_transform, image_plane_shape = pm.imagePlane( fileName=context["representation"]["data"]["path"], - camera=camera, showInAllViews=is_in_all_views - ) + camera=camera) image_plane_shape.depth.set(image_plane_depth) - if is_static_image_plane: - image_plane_shape.detach() - image_plane_transform.setRotation(camera.getRotation()) + # if is_static_image_plane: + # image_plane_shape.detach() + # image_plane_transform.setRotation(camera.getRotation()) start_frame = pm.playbackOptions(q=True, min=True) end_frame = pm.playbackOptions(q=True, max=True) - image_plane_shape.frameOffset.set(1 - start_frame) + if int(start_frame) > 0: + image_plane_shape.frameOffset.set(int(start_frame)- 1) + else: + image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) image_plane_shape.frameCache.set(end_frame) @@ -180,9 +182,13 @@ class ImagePlaneLoader(load.LoaderPlugin): QtWidgets.QMessageBox.Cancel ) if reply == QtWidgets.QMessageBox.Ok: - pm.delete( - image_plane_shape.listConnections(type="expression")[0] - ) + expressions = image_plane_shape.frameExtension.inputs(type="expression") + if expressions: + pm.delete(expressions) + + if not image_plane_shape.frameExtension.isFreeToChange(): + raise RuntimeError("Can't set frame extension for {}".format(image_plane_shape)) + image_plane_shape.frameExtension.set(start_frame) new_nodes.extend( @@ -233,7 +239,10 @@ class ImagePlaneLoader(load.LoaderPlugin): ) start_frame = asset["data"]["frameStart"] end_frame = asset["data"]["frameEnd"] - image_plane_shape.frameOffset.set(1 - start_frame) + if int(start_frame) > 0: + image_plane_shape.frameOffset.set(int(start_frame)- 1) + else: + image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) image_plane_shape.frameCache.set(end_frame) From f09ca54d962e34735b000595889c5d54c88e2fc0 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 14 Dec 2022 15:04:34 +0800 Subject: [PATCH 116/211] bug fix image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 82c2676982..33ae61ec0d 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -23,8 +23,6 @@ class CameraWindow(QtWidgets.QDialog): self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint) self.camera = None - # self.static_image_plane = False - # self.show_in_all_views = False self.widgets = { "label": QtWidgets.QLabel("Select camera for image plane."), @@ -45,8 +43,6 @@ class CameraWindow(QtWidgets.QDialog): for camera in cameras: self.widgets["list"].addItem(camera) - # self.widgets["staticImagePlane"].setText("Make Image Plane Static") - # self.widgets["showInAllViews"].setText("Show Image Plane in All Views") # Build buttons. layout = QtWidgets.QHBoxLayout(self.widgets["buttons"]) @@ -57,8 +53,6 @@ class CameraWindow(QtWidgets.QDialog): layout = QtWidgets.QVBoxLayout(self) layout.addWidget(self.widgets["label"]) layout.addWidget(self.widgets["list"]) - # layout.addWidget(self.widgets["staticImagePlane"]) - # layout.addWidget(self.widgets["showInAllViews"]) layout.addWidget(self.widgets["buttons"]) layout.addWidget(self.widgets["warning"]) @@ -73,8 +67,6 @@ class CameraWindow(QtWidgets.QDialog): if self.camera is None: self.widgets["warning"].setVisible(True) return - # self.show_in_all_views = self.widgets["showInAllViews"].isChecked() - # self.static_image_plane = self.widgets["staticImagePlane"].isChecked() self.close() From 29ee8e5edb46dc58b70dfa8b78eba3a1e5c07b68 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 14 Dec 2022 15:05:42 +0800 Subject: [PATCH 117/211] bug fix image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 33ae61ec0d..cc03787a6b 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -179,7 +179,7 @@ class ImagePlaneLoader(load.LoaderPlugin): pm.delete(expressions) if not image_plane_shape.frameExtension.isFreeToChange(): - raise RuntimeError("Can't set frame extension for {}".format(image_plane_shape)) + raise RuntimeError("Can't set frame extension for {}".format(image_plane_shape)) # noqa image_plane_shape.frameExtension.set(start_frame) From 1522d78873eb5c0ce34970b0eb4c48a74d8f594b Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 14 Dec 2022 15:07:47 +0800 Subject: [PATCH 118/211] bug fix image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index cc03787a6b..4055dc50b0 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -102,8 +102,6 @@ class ImagePlaneLoader(load.LoaderPlugin): # is_in_all_views = None if data: camera = pm.PyNode(data.get("camera")) - # is_static_image_plane = data.get("static_image_plane") - # is_in_all_views = data.get("in_all_views") if not camera: cameras = pm.ls(type="camera") @@ -113,9 +111,6 @@ class ImagePlaneLoader(load.LoaderPlugin): window.exec_() camera = camera_names[window.camera] - # is_static_image_plane = window.static_image_plane - # is_in_all_views = window.show_in_all_views - if camera == "create_camera": camera = pm.createNode("camera") @@ -134,15 +129,12 @@ class ImagePlaneLoader(load.LoaderPlugin): camera=camera) image_plane_shape.depth.set(image_plane_depth) - # if is_static_image_plane: - # image_plane_shape.detach() - # image_plane_transform.setRotation(camera.getRotation()) start_frame = pm.playbackOptions(q=True, min=True) end_frame = pm.playbackOptions(q=True, max=True) if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame)- 1) + image_plane_shape.frameOffset.set(int(start_frame)-1) else: image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) @@ -232,7 +224,7 @@ class ImagePlaneLoader(load.LoaderPlugin): start_frame = asset["data"]["frameStart"] end_frame = asset["data"]["frameEnd"] if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame)- 1) + image_plane_shape.frameOffset.set(int(start_frame)-1) else: image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) From 916b5b82afd4779c3e1c099aee3fae300e8e55cb Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 14 Dec 2022 15:10:08 +0800 Subject: [PATCH 119/211] bug fix image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 4055dc50b0..5f1c582203 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -134,7 +134,7 @@ class ImagePlaneLoader(load.LoaderPlugin): end_frame = pm.playbackOptions(q=True, max=True) if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame)-1) + image_plane_shape.frameOffset.set(int(start_frame) - 1) else: image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) @@ -166,7 +166,7 @@ class ImagePlaneLoader(load.LoaderPlugin): QtWidgets.QMessageBox.Cancel ) if reply == QtWidgets.QMessageBox.Ok: - expressions = image_plane_shape.frameExtension.inputs(type="expression") + expressions = image_plane_shape.frameExtension.inputs(type="expression") # noqa if expressions: pm.delete(expressions) @@ -224,7 +224,7 @@ class ImagePlaneLoader(load.LoaderPlugin): start_frame = asset["data"]["frameStart"] end_frame = asset["data"]["frameEnd"] if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame)-1) + image_plane_shape.frameOffset.set(int(start_frame) - 1) else: image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) From 0c481f83510438c5fb6243baa3f5c83adba6dbf6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 15 Dec 2022 11:55:14 +0100 Subject: [PATCH 120/211] OP-4512 - safer resolution of enabled If new site is added in System setting, but project settings are not saved, 'enabled' key is missing. This should be safer in this cases. --- openpype/modules/sync_server/providers/dropbox.py | 2 +- openpype/modules/sync_server/providers/gdrive.py | 2 +- openpype/modules/sync_server/providers/sftp.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/modules/sync_server/providers/dropbox.py b/openpype/modules/sync_server/providers/dropbox.py index e026ae7ef6..3515aee93f 100644 --- a/openpype/modules/sync_server/providers/dropbox.py +++ b/openpype/modules/sync_server/providers/dropbox.py @@ -22,7 +22,7 @@ class DropboxHandler(AbstractProvider): ) return - if not self.presets["enabled"]: + if not self.presets.get("enabled"): self.log.debug("Sync Server: Site {} not enabled for {}.". format(site_name, project_name)) return diff --git a/openpype/modules/sync_server/providers/gdrive.py b/openpype/modules/sync_server/providers/gdrive.py index 9a3ce89cf5..297a5c9fec 100644 --- a/openpype/modules/sync_server/providers/gdrive.py +++ b/openpype/modules/sync_server/providers/gdrive.py @@ -74,7 +74,7 @@ class GDriveHandler(AbstractProvider): ) return - if not self.presets["enabled"]: + if not self.presets.get("enabled"): self.log.debug( "Sync Server: Site {} not enabled for {}.".format( site_name, project_name diff --git a/openpype/modules/sync_server/providers/sftp.py b/openpype/modules/sync_server/providers/sftp.py index 40f11cb9dd..1b4f68c585 100644 --- a/openpype/modules/sync_server/providers/sftp.py +++ b/openpype/modules/sync_server/providers/sftp.py @@ -72,7 +72,7 @@ class SFTPHandler(AbstractProvider): Returns: (boolean) """ - return self.presets["enabled"] and self.conn is not None + return self.self.presets.get("enabled") and self.conn is not None @classmethod def get_system_settings_schema(cls): From 753c876d9fd393f5f64bbf0392a91c89380bbf78 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 15 Dec 2022 11:59:01 +0100 Subject: [PATCH 121/211] OP-4512 - create Anatomy object only for default local sites Eg. studio and local id of machine. It doesn't make much sense for Anatomy to handle other SiteSync sites. --- openpype/pipeline/anatomy.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index 908dc2b187..5b4eb67247 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -24,6 +24,7 @@ from openpype.lib.path_templates import ( FormatObject, ) from openpype.lib.log import Logger +from openpype.lib import get_local_site_id log = Logger.get_logger(__name__) @@ -60,6 +61,10 @@ class BaseAnatomy(object): project_name = project_doc["name"] self.project_name = project_name + if site_name not in ["studio", get_local_site_id()]: + raise RuntimeError("Anatomy could be created only for default " + "local sites") + self._site_name = site_name self._data = self._prepare_anatomy_data( From 19ab86499a79cab738daef25850781f1409519b4 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 15 Dec 2022 12:00:10 +0100 Subject: [PATCH 122/211] OP-4512 - update method to get all configured sites Added more details to be more useful. --- .../modules/sync_server/sync_server_module.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index 653ee50541..034121d996 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -1368,13 +1368,19 @@ class SyncServerModule(OpenPypeModule, ITrayModule): """ sync_sett = self.sync_system_settings project_enabled = True + project_settings = None if project_name: project_enabled = project_name in self.get_enabled_projects() + project_settings = self.get_sync_project_setting(project_name) sync_enabled = sync_sett["enabled"] and project_enabled system_sites = {} if sync_enabled: for site, detail in sync_sett.get("sites", {}).items(): + if project_settings: + site_settings = project_settings["sites"].get(site) + if site_settings: + detail.update(site_settings) system_sites[site] = detail system_sites.update(self._get_default_site_configs(sync_enabled, @@ -1396,14 +1402,22 @@ class SyncServerModule(OpenPypeModule, ITrayModule): exclude_locals=True) roots = {} for root, config in anatomy_sett["roots"].items(): - roots[root] = config[platform.system().lower()] + roots[root] = config studio_config = { + 'enabled': True, 'provider': 'local_drive', "root": roots } all_sites = {self.DEFAULT_SITE: studio_config} if sync_enabled: - all_sites[get_local_site_id()] = {'provider': 'local_drive'} + all_sites[get_local_site_id()] = {'enabled': True, + 'provider': 'local_drive', + "root": roots} + # duplicate values for normalized local name + all_sites["local"] = { + 'enabled': True, + 'provider': 'local_drive', + "root": roots} return all_sites def get_provider_for_site(self, project_name=None, site=None): From e29f8d445b762545b4dbe7f7227f668cdabd7bac Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 15 Dec 2022 12:05:42 +0100 Subject: [PATCH 123/211] OP-4512 - updated way to get sites Labels for roots are now actually changing according to selected sites --- .../local_settings/projects_widget.py | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/openpype/tools/settings/local_settings/projects_widget.py b/openpype/tools/settings/local_settings/projects_widget.py index 30a0d212f0..2b8c56e38c 100644 --- a/openpype/tools/settings/local_settings/projects_widget.py +++ b/openpype/tools/settings/local_settings/projects_widget.py @@ -248,6 +248,9 @@ class SitesWidget(QtWidgets.QWidget): main_layout.addWidget(comboboxes_widget, 0) main_layout.addWidget(content_widget, 1) + active_site_widget.value_changed.connect(self.refresh) + remote_site_widget.value_changed.connect(self.refresh) + self.active_site_widget = active_site_widget self.remote_site_widget = remote_site_widget @@ -268,25 +271,29 @@ class SitesWidget(QtWidgets.QWidget): self.modules_manager.modules_by_name["sync_server"] ) - # This is temporary modification - # - whole logic here should be in sync module's providers - site_names = sync_server_module.get_active_sites_from_settings( - self.project_settings["project_settings"].value - ) + site_configs = sync_server_module.get_all_site_configs( + self._project_name) roots_entity = ( self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] ) - + site_names = [self.active_site_widget.current_text(), + self.remote_site_widget.current_text()] output = [] for site_name in site_names: + if not site_name: + continue + site_inputs = [] - for root_name, path_entity in roots_entity.items(): - platform_entity = path_entity[platform.system().lower()] + site_config = site_configs[site_name] + for root_name, path_entity in site_config.get("root", {}).items(): + if not path_entity: + continue + platform_value = path_entity[platform.system().lower()] site_inputs.append({ "label": root_name, "key": root_name, - "value": platform_entity.value + "value": platform_value }) output.append( @@ -436,6 +443,7 @@ class SitesWidget(QtWidgets.QWidget): class _SiteCombobox(QtWidgets.QWidget): input_label = None + value_changed = QtCore.Signal() def __init__(self, modules_manager, project_settings, parent): super(_SiteCombobox, self).__init__(parent) @@ -661,6 +669,7 @@ class _SiteCombobox(QtWidgets.QWidget): self._set_local_settings_value(self.current_text()) self._update_style() + self.value_changed.emit() def _set_local_settings_value(self, value): raise NotImplementedError( From 61076ae7dbdf50541f9b465e0cfdc18ebe0740ef Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 15 Dec 2022 19:45:29 +0800 Subject: [PATCH 124/211] fix the setAttr error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 5f1c582203..6f8925a083 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -166,13 +166,17 @@ class ImagePlaneLoader(load.LoaderPlugin): QtWidgets.QMessageBox.Cancel ) if reply == QtWidgets.QMessageBox.Ok: - expressions = image_plane_shape.frameExtension.inputs(type="expression") # noqa + # find the input and output of frame extension + expressions = image_plane_shape.frameExtension.inputs() + frame_ext_output = image_plane_shape.frameExtension.outputs() if expressions: - pm.delete(expressions) + # the "time1" node is non-deletable attr + # in Maya, use disconnectAttr instead + pm.disconnectAttr(expressions, frame_ext_output) if not image_plane_shape.frameExtension.isFreeToChange(): raise RuntimeError("Can't set frame extension for {}".format(image_plane_shape)) # noqa - + # get the node of time instead and set the time for it. image_plane_shape.frameExtension.set(start_frame) new_nodes.extend( From 9522607a242a2d8fc55e1c4e316474b0b9a09502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Fri, 16 Dec 2022 11:07:26 +0100 Subject: [PATCH 125/211] Update openpype/hosts/nuke/api/pipeline.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 268d25b68e..7fd22a0062 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -78,7 +78,7 @@ if os.getenv("PYBLISH_GUI", None): class NukeHost( - HostBase, IWorkfileHost, ILoadHost, INewPublisher + HostBase, IWorkfileHost, ILoadHost, IPublishHost ): name = "nuke" From e807d7e275eb3d159b61fac28073b9b081e83c18 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 16 Dec 2022 18:10:56 +0800 Subject: [PATCH 126/211] Update load_image_plane.py set the frame offset to zero by default --- openpype/hosts/maya/plugins/load/load_image_plane.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 6f8925a083..86816495ae 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -133,10 +133,7 @@ class ImagePlaneLoader(load.LoaderPlugin): start_frame = pm.playbackOptions(q=True, min=True) end_frame = pm.playbackOptions(q=True, max=True) - if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame) - 1) - else: - image_plane_shape.frameOffset.set(int(start_frame)) + image_plane_shape.frameOffset.set(0) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) image_plane_shape.frameCache.set(end_frame) @@ -227,10 +224,8 @@ class ImagePlaneLoader(load.LoaderPlugin): ) start_frame = asset["data"]["frameStart"] end_frame = asset["data"]["frameEnd"] - if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame) - 1) - else: - image_plane_shape.frameOffset.set(int(start_frame)) + + image_plane_shape.frameOffset.set(0) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) image_plane_shape.frameCache.set(end_frame) From 208d5950e433f5434cf51c4be02e87f13f92c289 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Dec 2022 14:46:45 +0100 Subject: [PATCH 127/211] fix resize of update dialog if the version is too long --- igniter/update_window.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/igniter/update_window.py b/igniter/update_window.py index d7908c240b..bc3a28e9af 100644 --- a/igniter/update_window.py +++ b/igniter/update_window.py @@ -47,7 +47,6 @@ class UpdateWindow(QtWidgets.QDialog): self._update_thread = None - self.resize(QtCore.QSize(self._width, self._height)) self._init_ui() # Set stylesheet @@ -79,6 +78,16 @@ class UpdateWindow(QtWidgets.QDialog): self._progress_bar = progress_bar + def showEvent(self, event): + super().showEvent(event) + current_size = self.size() + new_size = QtCore.QSize( + max(current_size.width(), self._width), + max(current_size.height(), self._height) + ) + if current_size != new_size: + self.resize(new_size) + def _run_update(self): """Start install process. From e0a2f2370256212f2ea78f282a9dc3eeb156b362 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 16 Dec 2022 16:35:14 +0100 Subject: [PATCH 128/211] :bug: fix node access --- openpype/hosts/houdini/plugins/create/create_hda.py | 2 +- openpype/hosts/houdini/plugins/publish/collect_active_state.py | 2 +- openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py | 2 +- openpype/hosts/houdini/plugins/publish/collect_usd_layers.py | 3 ++- .../hosts/houdini/plugins/publish/extract_redshift_proxy.py | 2 +- openpype/hosts/houdini/plugins/publish/extract_usd.py | 2 +- openpype/hosts/houdini/plugins/publish/extract_usd_layered.py | 2 +- openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py | 2 +- .../houdini/plugins/publish/validate_animation_settings.py | 3 +-- openpype/hosts/houdini/plugins/publish/validate_bypass.py | 2 +- .../hosts/houdini/plugins/publish/validate_cop_output_node.py | 2 +- openpype/hosts/houdini/plugins/publish/validate_frame_token.py | 3 +-- openpype/hosts/houdini/plugins/publish/validate_no_errors.py | 2 +- .../plugins/publish/validate_usd_layer_path_backslashes.py | 2 +- .../houdini/plugins/publish/validate_usd_model_and_shade.py | 2 +- .../hosts/houdini/plugins/publish/validate_usd_output_node.py | 2 +- .../hosts/houdini/plugins/publish/validate_usd_setdress.py | 2 +- .../houdini/plugins/publish/validate_usd_shade_workspace.py | 2 +- .../hosts/houdini/plugins/publish/validate_vdb_output_node.py | 2 +- 19 files changed, 20 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/houdini/plugins/create/create_hda.py b/openpype/hosts/houdini/plugins/create/create_hda.py index 4bed83c2e9..5f95b2efb4 100644 --- a/openpype/hosts/houdini/plugins/create/create_hda.py +++ b/openpype/hosts/houdini/plugins/create/create_hda.py @@ -34,7 +34,7 @@ class CreateHDA(plugin.HoudiniCreator): } return subset_name.lower() in existing_subset_names_low - def _create_instance_node( + def create_instance_node( self, node_name, parent, node_type="geometry"): import hou diff --git a/openpype/hosts/houdini/plugins/publish/collect_active_state.py b/openpype/hosts/houdini/plugins/publish/collect_active_state.py index cc3f2e7fae..7fda94b288 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_active_state.py +++ b/openpype/hosts/houdini/plugins/publish/collect_active_state.py @@ -25,7 +25,7 @@ class CollectInstanceActiveState(pyblish.api.InstancePlugin): # Check bypass state and reverse active = True - node = hou.node(instance.get("instance_node")) + node = hou.node(instance.data.get("instance_node")) if hasattr(node, "isBypassed"): active = not node.isBypassed() diff --git a/openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py b/openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py index 346bdf3421..f1d73d7523 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py +++ b/openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py @@ -69,7 +69,7 @@ class CollectRedshiftROPRenderProducts(pyblish.api.InstancePlugin): def process(self, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) # Collect chunkSize chunk_size_parm = rop.parm("chunkSize") diff --git a/openpype/hosts/houdini/plugins/publish/collect_usd_layers.py b/openpype/hosts/houdini/plugins/publish/collect_usd_layers.py index 833add854b..696560a590 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_usd_layers.py +++ b/openpype/hosts/houdini/plugins/publish/collect_usd_layers.py @@ -21,7 +21,7 @@ class CollectUsdLayers(pyblish.api.InstancePlugin): self.log.debug("No output node found..") return - rop_node = hou.node(instance.get("instance_node")) + rop_node = hou.node(instance.data["instance_node"]) save_layers = [] for layer in usdlib.get_configured_save_layers(rop_node): @@ -56,6 +56,7 @@ class CollectUsdLayers(pyblish.api.InstancePlugin): layer_inst.data["subset"] = "__stub__" layer_inst.data["label"] = label layer_inst.data["asset"] = instance.data["asset"] + layer_inst.data["instance_node"] = instance.data["instance_node"] # include same USD ROP layer_inst.append(rop_node) # include layer data diff --git a/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py b/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py index 29ede98a52..1d99ac665c 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py +++ b/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py @@ -17,7 +17,7 @@ class ExtractRedshiftProxy(publish.Extractor): def process(self, instance): - ropnode = hou.node(instance.get("instance_node")) + ropnode = hou.node(instance.data.get("instance_node")) # Get the filename from the filename parameter # `.evalParm(parameter)` will make sure all tokens are resolved diff --git a/openpype/hosts/houdini/plugins/publish/extract_usd.py b/openpype/hosts/houdini/plugins/publish/extract_usd.py index cbeb5add71..61c1b477b2 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_usd.py +++ b/openpype/hosts/houdini/plugins/publish/extract_usd.py @@ -18,7 +18,7 @@ class ExtractUSD(publish.Extractor): def process(self, instance): - ropnode = hou.node(instance.get("instance_node")) + ropnode = hou.node(instance.data.get("instance_node")) # Get the filename from the filename parameter output = ropnode.evalParm("lopoutput") diff --git a/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py b/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py index 0288b7363a..8422a3bc3e 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py +++ b/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py @@ -187,7 +187,7 @@ class ExtractUSDLayered(publish.Extractor): # Main ROP node, either a USD Rop or ROP network with # multiple USD ROPs - node = hou.node(instance.get("instance_node")) + node = hou.node(instance.data["instance_node"]) # Collect any output dependencies that have not been processed yet # during extraction of other instances diff --git a/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py b/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py index 434d6a2160..4bca758f08 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py +++ b/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py @@ -17,7 +17,7 @@ class ExtractVDBCache(publish.Extractor): def process(self, instance): - ropnode = hou.node(instance.get("instance_node")) + ropnode = hou.node(instance.data["instance_node"]) # Get the filename from the filename parameter # `.evalParm(parameter)` will make sure all tokens are resolved diff --git a/openpype/hosts/houdini/plugins/publish/validate_animation_settings.py b/openpype/hosts/houdini/plugins/publish/validate_animation_settings.py index f11f9c0c62..4878738ed3 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_animation_settings.py +++ b/openpype/hosts/houdini/plugins/publish/validate_animation_settings.py @@ -37,8 +37,7 @@ class ValidateAnimationSettings(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - node = hou.node(instance.get("instance_node")) - + node = hou.node(instance.data["instance_node"]) # Check trange parm, 0 means Render Current Frame frame_range = node.evalParm("trange") if frame_range == 0: diff --git a/openpype/hosts/houdini/plugins/publish/validate_bypass.py b/openpype/hosts/houdini/plugins/publish/validate_bypass.py index 1bf51a986c..c10c5a2c05 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_bypass.py +++ b/openpype/hosts/houdini/plugins/publish/validate_bypass.py @@ -37,6 +37,6 @@ class ValidateBypassed(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data["instance_node"]) if hasattr(rop, "isBypassed") and rop.isBypassed(): return [rop] diff --git a/openpype/hosts/houdini/plugins/publish/validate_cop_output_node.py b/openpype/hosts/houdini/plugins/publish/validate_cop_output_node.py index 1d0377c818..1fc767b309 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_cop_output_node.py +++ b/openpype/hosts/houdini/plugins/publish/validate_cop_output_node.py @@ -48,7 +48,7 @@ class ValidateCopOutputNode(pyblish.api.InstancePlugin): ) if output_node is None: - node = hou.node(instance.get("instance_node")) + node = hou.node(instance.data.get("instance_node")) cls.log.error( "COP Output node in '%s' does not exist. " "Ensure a valid COP output path is set." % node.path() diff --git a/openpype/hosts/houdini/plugins/publish/validate_frame_token.py b/openpype/hosts/houdini/plugins/publish/validate_frame_token.py index b5f6ba71e1..06d4003295 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_frame_token.py +++ b/openpype/hosts/houdini/plugins/publish/validate_frame_token.py @@ -37,8 +37,7 @@ class ValidateFrameToken(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - node = hou.node(instance.get("instance_node")) - + node = hou.node(instance.data["instance_node"]) # Check trange parm, 0 means Render Current Frame frame_range = node.evalParm("trange") if frame_range == 0: diff --git a/openpype/hosts/houdini/plugins/publish/validate_no_errors.py b/openpype/hosts/houdini/plugins/publish/validate_no_errors.py index f7c95aaf4e..6c48eae70a 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_no_errors.py +++ b/openpype/hosts/houdini/plugins/publish/validate_no_errors.py @@ -38,7 +38,7 @@ class ValidateNoErrors(pyblish.api.InstancePlugin): validate_nodes = [] if len(instance) > 0: - validate_nodes.append(hou.node(instance.get("instance_node"))) + validate_nodes.append(hou.node(instance.data.get("instance_node"))) output_node = instance.data.get("output_node") if output_node: validate_nodes.append(output_node) diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_layer_path_backslashes.py b/openpype/hosts/houdini/plugins/publish/validate_usd_layer_path_backslashes.py index a0e2302495..f2c7878c4e 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_layer_path_backslashes.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_layer_path_backslashes.py @@ -28,7 +28,7 @@ class ValidateUSDLayerPathBackslashes(pyblish.api.InstancePlugin): def process(self, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) lop_path = hou_usdlib.get_usd_rop_loppath(rop) stage = lop_path.stage(apply_viewport_overrides=False) diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_model_and_shade.py b/openpype/hosts/houdini/plugins/publish/validate_usd_model_and_shade.py index a55eb70cb2..b8faae16d7 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_model_and_shade.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_model_and_shade.py @@ -40,7 +40,7 @@ class ValidateUsdModel(pyblish.api.InstancePlugin): def process(self, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) lop_path = hou_usdlib.get_usd_rop_loppath(rop) stage = lop_path.stage(apply_viewport_overrides=False) diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_output_node.py b/openpype/hosts/houdini/plugins/publish/validate_usd_output_node.py index af21efcafc..5cb5bd35fb 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_output_node.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_output_node.py @@ -36,7 +36,7 @@ class ValidateUSDOutputNode(pyblish.api.InstancePlugin): output_node = instance.data["output_node"] if output_node is None: - node = hou.node(instance.get("instance_node")) + node = hou.node(instance.data.get("instance_node")) cls.log.error( "USD node '%s' LOP path does not exist. " "Ensure a valid LOP path is set." % node.path() diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_setdress.py b/openpype/hosts/houdini/plugins/publish/validate_usd_setdress.py index 01ebc0e828..b96d185482 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_setdress.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_setdress.py @@ -24,7 +24,7 @@ class ValidateUsdSetDress(pyblish.api.InstancePlugin): from pxr import UsdGeom import hou - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) lop_path = hou_usdlib.get_usd_rop_loppath(rop) stage = lop_path.stage(apply_viewport_overrides=False) diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_shade_workspace.py b/openpype/hosts/houdini/plugins/publish/validate_usd_shade_workspace.py index bd3366a424..cb2099437d 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_shade_workspace.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_shade_workspace.py @@ -20,7 +20,7 @@ class ValidateUsdShadeWorkspace(pyblish.api.InstancePlugin): def process(self, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) workspace = rop.parent() definition = workspace.type().definition() diff --git a/openpype/hosts/houdini/plugins/publish/validate_vdb_output_node.py b/openpype/hosts/houdini/plugins/publish/validate_vdb_output_node.py index 61c1209fc9..f9f88b3bf9 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_vdb_output_node.py +++ b/openpype/hosts/houdini/plugins/publish/validate_vdb_output_node.py @@ -38,7 +38,7 @@ class ValidateVDBOutputNode(pyblish.api.InstancePlugin): if node is None: cls.log.error( "SOP path is not correctly set on " - "ROP node '%s'." % instance.get("instance_node") + "ROP node '%s'." % instance.data.get("instance_node") ) return [instance] From b06ea8c03352affbc64a6d70b28037e67d6e3f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 19 Dec 2022 13:33:02 +0100 Subject: [PATCH 129/211] Update openpype/hosts/nuke/api/pipeline.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 7fd22a0062..eb468d97c1 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -11,7 +11,7 @@ from openpype.host import ( HostBase, IWorkfileHost, ILoadHost, - INewPublisher + IPublishHost ) from openpype.settings import get_current_project_settings from openpype.lib import register_event_callback, Logger From d439eec880c2703aba86b5500d28757a9bf00f25 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 18:36:27 +0800 Subject: [PATCH 130/211] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 86816495ae..664cd06fc1 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -72,6 +72,8 @@ class CameraWindow(QtWidgets.QDialog): def on_cancel_pressed(self): self.camera = None + if self.camera: + return self.close() From 8055b793ee7bd1d90466bb0cd3f6334779ba1a8c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 18:45:14 +0800 Subject: [PATCH 131/211] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 664cd06fc1..ce752f170f 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,8 +71,7 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - self.camera = None - if self.camera: + if self.camera is not None: return self.close() From 9173199896975fe5d2a20e8ec99019fe1987140b Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 18:46:06 +0800 Subject: [PATCH 132/211] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index ce752f170f..081c646298 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,7 +71,7 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - if self.camera is not None: + if self.camera: return self.close() From cd9f14a21d999a50e01d2ed9ce0f744a17af829c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 19:09:17 +0800 Subject: [PATCH 133/211] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 081c646298..c18cb5c6c8 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -57,7 +57,7 @@ class CameraWindow(QtWidgets.QDialog): layout.addWidget(self.widgets["warning"]) self.widgets["okButton"].pressed.connect(self.on_ok_pressed) - self.widgets["cancelButton"].clicked.connect(self.on_cancel_pressed) + self.widgets["cancelButton"].pressed.connect(self.on_cancel_pressed) self.widgets["list"].itemPressed.connect(self.on_list_itemPressed) def on_list_itemPressed(self, item): @@ -71,8 +71,6 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - if self.camera: - return self.close() From 32f87d6324702dc24b86123d97bef40ec353a0de Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 19:47:07 +0800 Subject: [PATCH 134/211] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index c18cb5c6c8..7d5d4cb12b 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,8 +71,10 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - self.close() + if self.camera is None: + return + self.close() class ImagePlaneLoader(load.LoaderPlugin): """Specific loader of plate for image planes on selected camera.""" From 20b85799e2f1c219254a42be2232398d8650351c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 21:16:19 +0800 Subject: [PATCH 135/211] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 7d5d4cb12b..5075e4b8fe 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,6 +71,7 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): + self.camera = None if self.camera is None: return From 6a4261d81a001874f4ac26f72514a70f3a34dea6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 21:58:50 +0800 Subject: [PATCH 136/211] maya load image plane error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 5075e4b8fe..2bfe6cb766 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,12 +71,10 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - self.camera = None - if self.camera is None: + if self.camera or self.camera is None: + self.close() return - self.close() - class ImagePlaneLoader(load.LoaderPlugin): """Specific loader of plate for image planes on selected camera.""" From 0b8b2eb03a03eb25bb399d0b4d25c75b154792ca Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 22:33:04 +0800 Subject: [PATCH 137/211] maya load image plane error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 2bfe6cb766..9eb4c7f561 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,9 +71,8 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - if self.camera or self.camera is None: - self.close() - return + self.camera = None + self.close() class ImagePlaneLoader(load.LoaderPlugin): """Specific loader of plate for image planes on selected camera.""" @@ -109,7 +108,10 @@ class ImagePlaneLoader(load.LoaderPlugin): camera_names["Create new camera."] = "create_camera" window = CameraWindow(camera_names.keys()) window.exec_() - camera = camera_names[window.camera] + try: + camera = camera_names[window.camera] + except KeyError: + pass if camera == "create_camera": camera = pm.createNode("camera") From c597a12601415fb6cf90f680606915b8dc2b3bcb Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 21 Dec 2022 00:14:32 +0800 Subject: [PATCH 138/211] maya-image-plane-load-error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 9eb4c7f561..f77b755050 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -108,10 +108,10 @@ class ImagePlaneLoader(load.LoaderPlugin): camera_names["Create new camera."] = "create_camera" window = CameraWindow(camera_names.keys()) window.exec_() - try: - camera = camera_names[window.camera] - except KeyError: - pass + # Skip if no camera was selected (Dialog was closed) + if window.camera not in camera_names: + return + camera = camera_names[window.camera] if camera == "create_camera": camera = pm.createNode("camera") From 34f2c15d2dc2fa688026c46d1a8d72164321ee7e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 21 Dec 2022 16:28:50 +0100 Subject: [PATCH 139/211] hiero: creator gui with min max --- openpype/hosts/hiero/api/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index 38933a1e30..07457db1a4 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -276,8 +276,8 @@ class CreatorWidget(QtWidgets.QDialog): elif v["type"] == "QSpinBox": data[k]["value"] = self.create_row( content_layout, "QSpinBox", v["label"], - setRange=(1, 9999999), setValue=v["value"], - setToolTip=tool_tip) + setValue=v["value"], setMinimum=0, + setMaximum=100000, setToolTip=tool_tip) return data From a15d41e00b8956f10bda95f2a84d55f3b0081e16 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 22 Dec 2022 11:19:47 +0100 Subject: [PATCH 140/211] OP-4512 - add 'local' to default sites It seems that local label could come too. --- openpype/pipeline/anatomy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index 5b4eb67247..491ea48413 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -61,7 +61,7 @@ class BaseAnatomy(object): project_name = project_doc["name"] self.project_name = project_name - if site_name not in ["studio", get_local_site_id()]: + if site_name not in ["studio", "local", get_local_site_id()]: raise RuntimeError("Anatomy could be created only for default " "local sites") From 56cdcf3445bf49f97b86db5fade7833c2bb45c17 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 22 Dec 2022 11:21:15 +0100 Subject: [PATCH 141/211] OP-4512 - added better logging --- openpype/pipeline/anatomy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index 491ea48413..a6750ede7c 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -63,7 +63,7 @@ class BaseAnatomy(object): if site_name not in ["studio", "local", get_local_site_id()]: raise RuntimeError("Anatomy could be created only for default " - "local sites") + "local sites not for {}".format(site_name)) self._site_name = site_name From 95b15a9f00bbcd5f7bd0e241e3818ee6b6d64c9d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 22 Dec 2022 11:44:35 +0100 Subject: [PATCH 142/211] global,nuke,maya: on demand placeholder removal preset attribute --- .../maya/api/workfile_template_builder.py | 2 +- .../nuke/api/workfile_template_builder.py | 15 ++++-- .../workfile/workfile_template_builder.py | 49 +++++++++++++++---- .../schema_templated_workfile_build.json | 11 ++++- 4 files changed, 62 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index ef043ed0f4..1d3f1cf568 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -28,7 +28,7 @@ class MayaTemplateBuilder(AbstractTemplateBuilder): Args: path (str): A path to current template (usually given by - get_template_path implementation) + get_template_preset implementation) Returns: bool: Wether the template was succesfully imported or not diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 7a2e442e32..60bf906fbe 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -40,7 +40,7 @@ class NukeTemplateBuilder(AbstractTemplateBuilder): Args: path (str): A path to current template (usually given by - get_template_path implementation) + get_template_preset implementation) Returns: bool: Wether the template was succesfully imported or not @@ -273,6 +273,15 @@ class NukePlaceholderLoadPlugin(NukePlaceholderPlugin, PlaceholderLoadMixin): placeholder.data["nb_children"] += 1 reset_selection() + + # remove placeholders marked as delete + if ( + placeholder.data.get("delete") + and not placeholder.data.get("keep_placeholder") + ): + self.log.debug("Deleting node: {}".format(placeholder_node.name())) + nuke.delete(placeholder_node) + # go back to root group nuke.root().begin() @@ -454,12 +463,12 @@ class NukePlaceholderLoadPlugin(NukePlaceholderPlugin, PlaceholderLoadMixin): ) for node in placeholder_node.dependent(): for idx in range(node.inputs()): - if node.input(idx) == placeholder_node: + if node.input(idx) == placeholder_node and output_node: node.setInput(idx, output_node) for node in placeholder_node.dependencies(): for idx in range(placeholder_node.inputs()): - if placeholder_node.input(idx) == node: + if placeholder_node.input(idx) == node and input_node: input_node.setInput(0, node) def _create_sib_copies(self, placeholder): diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 582657c735..f6a4ab51cb 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -401,7 +401,12 @@ class AbstractTemplateBuilder(object): key=lambda i: i.order )) - def build_template(self, template_path=None, level_limit=None): + def build_template( + self, + template_path=None, + level_limit=None, + keep_placeholders=None + ): """Main callback for building workfile from template path. Todo: @@ -410,16 +415,22 @@ class AbstractTemplateBuilder(object): Args: template_path (str): Path to a template file with placeholders. - Template from settings 'get_template_path' used when not + Template from settings 'get_template_preset' used when not passed. level_limit (int): Limit of populate loops. Related to 'populate_scene_placeholders' method. """ + template_preset = self.get_template_preset() if template_path is None: - template_path = self.get_template_path() + template_path = template_preset["path"] + + if keep_placeholders is None: + keep_placeholders = template_preset["placeholder_keep"] + self.import_template(template_path) - self.populate_scene_placeholders(level_limit) + self.populate_scene_placeholders( + level_limit, keep_placeholders) def rebuild_template(self): """Go through existing placeholders in scene and update them. @@ -489,7 +500,9 @@ class AbstractTemplateBuilder(object): plugin = plugins_by_identifier[identifier] plugin.prepare_placeholders(placeholders) - def populate_scene_placeholders(self, level_limit=None): + def populate_scene_placeholders( + self, level_limit=None, keep_placeholders=None + ): """Find placeholders in scene using plugins and process them. This should happen after 'import_template'. @@ -541,6 +554,11 @@ class AbstractTemplateBuilder(object): " is already in progress." )) continue + + # add flag for keeping placeholders in scene + # after they are processed + placeholder.data["keep_placeholder"] = keep_placeholders + filtered_placeholders.append(placeholder) self._prepare_placeholders(filtered_placeholders) @@ -599,8 +617,8 @@ class AbstractTemplateBuilder(object): ["profiles"] ) - def get_template_path(self): - """Unified way how template path is received usign settings. + def get_template_preset(self): + """Unified way how template preset is received usign settings. Method is dependent on '_get_build_profiles' which should return filter profiles to resolve path to a template. Default implementation looks @@ -637,6 +655,13 @@ class AbstractTemplateBuilder(object): ).format(task_name, task_type, host_name)) path = profile["path"] + + # switch to remove placeholders after they are used + placeholder_keep = profile.get("placeholder_keep") + # backward compatibility, since default is True + if placeholder_keep is not False: + placeholder_keep = True + if not path: raise TemplateLoadFailed(( "Template path is not set.\n" @@ -657,7 +682,10 @@ class AbstractTemplateBuilder(object): if path and os.path.exists(path): self.log.info("Found template at: '{}'".format(path)) - return path + return { + "path": path, + "placeholder_keep": placeholder_keep + } solved_path = None while True: @@ -683,7 +711,10 @@ class AbstractTemplateBuilder(object): self.log.info("Found template at: '{}'".format(solved_path)) - return solved_path + return { + "path": solved_path, + "placeholder_keep": placeholder_keep + } @six.add_metaclass(ABCMeta) diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json index 99a29beb27..1826734291 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json @@ -25,8 +25,15 @@ { "key": "path", "label": "Path to template", - "type": "text", - "object_type": "text" + "type": "path", + "multiplatform": false, + "multipath": false + }, + { + "key": "placeholder_keep", + "label": "Keep placeholders", + "type": "boolean", + "default": true } ] } From 011cd8f2e4e9536ce59194668d91b92712484ea1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 22 Dec 2022 11:45:38 +0100 Subject: [PATCH 143/211] nuke: remove update template menu item --- openpype/hosts/nuke/api/pipeline.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index fb707ca44c..918598c04f 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -217,10 +217,6 @@ def _install_menu(): "Build Workfile from template", lambda: build_workfile_template() ) - menu_template.addCommand( - "Update Workfile", - lambda: update_workfile_template() - ) menu_template.addSeparator() menu_template.addCommand( "Create Place Holder", From 90303d4137d3dfca49035ac1c878dbb830f42b42 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 22 Dec 2022 11:48:46 +0100 Subject: [PATCH 144/211] global: updating docstrings --- openpype/pipeline/workfile/workfile_template_builder.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index f6a4ab51cb..2850175bc9 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -419,6 +419,9 @@ class AbstractTemplateBuilder(object): passed. level_limit (int): Limit of populate loops. Related to 'populate_scene_placeholders' method. + keep_placeholders (bool): Add flag to placeholder data for + hosts to decide if they want to remove + placeholder after it is used. """ template_preset = self.get_template_preset() @@ -518,6 +521,9 @@ class AbstractTemplateBuilder(object): Args: level_limit (int): Level of loops that can happen. Default is 1000. + keep_placeholders (bool): Add flag to placeholder data for + hosts to decide if they want to remove + placeholder after it is used. """ if not self.placeholder_plugins: From 212b372c03dad76e7aa1a7b83148ea78dda5611e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 22 Dec 2022 11:49:18 +0100 Subject: [PATCH 145/211] nuke: make `get_group_io_nodes` soft fail --- openpype/hosts/nuke/api/lib.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index a066bbcdcf..2fdf446357 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2865,10 +2865,11 @@ def get_group_io_nodes(nodes): break if input_node is None: - raise ValueError("No Input found") + log.warning("No Input found") if output_node is None: - raise ValueError("No Output found") + log.warning("No Output found") + return input_node, output_node From 34e2ee9e7b36fd08d559c321019754cde71c03cd Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 22 Dec 2022 12:26:02 +0100 Subject: [PATCH 146/211] OP-4512 - fix typo --- openpype/modules/sync_server/providers/sftp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/sync_server/providers/sftp.py b/openpype/modules/sync_server/providers/sftp.py index 1b4f68c585..c41edc78bc 100644 --- a/openpype/modules/sync_server/providers/sftp.py +++ b/openpype/modules/sync_server/providers/sftp.py @@ -72,7 +72,7 @@ class SFTPHandler(AbstractProvider): Returns: (boolean) """ - return self.self.presets.get("enabled") and self.conn is not None + return self.presets.get("enabled") and self.conn is not None @classmethod def get_system_settings_schema(cls): From 1dc52fc3a22f3b7b29e4ce71ed1fca983498d9aa Mon Sep 17 00:00:00 2001 From: Joseff Date: Thu, 22 Dec 2022 15:08:04 +0100 Subject: [PATCH 147/211] Alter the UObject.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: OndÅ™ej Samohel <33513211+antirotor@users.noreply.github.com> --- .../UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h index 2df6c887cf..aca80946bb 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h @@ -3,7 +3,7 @@ #pragma once #include "CoreMinimal.h" -#include "Object.h" +#include "UObject/Object.h" #include "OpenPypeSettings.generated.h" #define OPENPYPE_SETTINGS_FILEPATH IPluginManager::Get().FindPlugin("OpenPype")->GetBaseDir() / TEXT("Config") / TEXT("DefaultOpenPypeSettings.ini") From d61d88d0a57fea3511eaf65954be0fba89e580ab Mon Sep 17 00:00:00 2001 From: Joseff Date: Thu, 22 Dec 2022 15:08:31 +0100 Subject: [PATCH 148/211] Alter the PluginManager and UObjectGlobals include. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: OndÅ™ej Samohel <33513211+antirotor@users.noreply.github.com> --- .../UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp index 7134614d22..a6b9eba749 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp @@ -2,8 +2,8 @@ #include "OpenPypeSettings.h" -#include "IPluginManager.h" -#include "UObjectGlobals.h" +#include "Interfaces/IPluginManager.h" +#include "UObject/UObjectGlobals.h" /** * Mainly is used for initializing default values if the DefaultOpenPypeSettings.ini file does not exist in the saved config From e34fee55fd5f0d00e745ab8d95663cb5be148b51 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 22 Dec 2022 15:54:07 +0100 Subject: [PATCH 149/211] Fix for empty site_name --- openpype/pipeline/anatomy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index a6750ede7c..627f7198bb 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -61,7 +61,8 @@ class BaseAnatomy(object): project_name = project_doc["name"] self.project_name = project_name - if site_name not in ["studio", "local", get_local_site_id()]: + if (site_name and + site_name not in ["studio", "local", get_local_site_id()]): raise RuntimeError("Anatomy could be created only for default " "local sites not for {}".format(site_name)) From f5cb893dc1b28b62b8132796bf5037d1236d6341 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 12:16:54 +0100 Subject: [PATCH 150/211] global: creator plugin abstraction for workfile builder template --- openpype/hosts/nuke/api/pipeline.py | 4 +- .../workfile/workfile_template_builder.py | 191 +++++++++++++++++- 2 files changed, 192 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 918598c04f..bdf12b7dc4 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -35,6 +35,7 @@ from .lib import ( ) from .workfile_template_builder import ( NukePlaceholderLoadPlugin, + NukePlaceholderCreatePlugin, build_workfile_template, update_workfile_template, create_placeholder, @@ -139,7 +140,8 @@ def _show_workfiles(): def get_workfile_build_placeholder_plugins(): return [ - NukePlaceholderLoadPlugin + NukePlaceholderLoadPlugin, + NukePlaceholderCreatePlugin ] diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 2850175bc9..d85d6b50dd 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -42,7 +42,10 @@ from openpype.pipeline.load import ( get_contexts_for_repre_docs, load_with_repre_context, ) -from openpype.pipeline.create import get_legacy_creator_by_name +from openpype.pipeline.create import ( + get_legacy_creator_by_name, + discover_legacy_creator_plugins +) class TemplateNotFound(Exception): @@ -235,7 +238,7 @@ class AbstractTemplateBuilder(object): def get_creators_by_name(self): if self._creators_by_name is None: - self._creators_by_name = get_legacy_creator_by_name() + self._creators_by_name = discover_legacy_creator_plugins() return self._creators_by_name def get_shared_data(self, key): @@ -1463,6 +1466,165 @@ class PlaceholderLoadMixin(object): pass +class PlaceholderCreateMixin(object): + """Mixin prepared for creating placeholder plugins. + + Implementation prepares options for placeholders with + 'get_create_plugin_options'. + + For placeholder population is implemented 'populate_create_placeholder'. + + PlaceholderItem can have implemented methods: + - 'create_failed' - called when creating of an instance failed + - 'create_succeed' - called when creating of an instance succeeded + """ + + def get_create_plugin_options(self, options=None): + """Unified attribute definitions for create placeholder. + + Common function for placeholder plugins used for creating of + publishable instances. Use it with 'get_placeholder_options'. + + Args: + plugin (PlaceholderPlugin): Plugin used for creating of + publish instances. + options (Dict[str, Any]): Already available options which are used + as defaults for attributes. + + Returns: + List[AbtractAttrDef]: Attribute definitions common for create + plugins. + """ + + creators_by_name = self.builder.get_creators_by_name() + creator_items = [ + (creator_name, creator.label or creator_name) + for creator_name, creator in creators_by_name.items() + ] + + creator_items = list(sorted(creator_items, key=lambda i: i[1])) + options = options or {} + return [ + attribute_definitions.UISeparatorDef(), + attribute_definitions.UILabelDef("Main attributes"), + attribute_definitions.UISeparatorDef(), + + attribute_definitions.EnumDef( + "creator", + label="Creator", + default=options.get("creator"), + items=creator_items, + tooltip=( + "Creator" + "\nDefines what OpenPype creator will be used to" + " create publishable instance." + "\nUseable creator depends on current host's creator list." + "\nField is case sensitive." + ) + ), + attribute_definitions.TextDef( + "create_variant", + label="Variant", + default=options.get("create_variant"), + placeholder='Main', + tooltip=( + "Creator" + "\nDefines variant name which will be use for " + "\ncompiling of subset name." + ) + ), + attribute_definitions.UISeparatorDef(), + attribute_definitions.NumberDef( + "order", + label="Order", + default=options.get("order") or 0, + decimals=0, + minimum=0, + maximum=999, + tooltip=( + "Order" + "\nOrder defines creating instance priority (0 to 999)" + "\nPriority rule is : \"lowest is first to load\"." + ) + ) + ] + + def populate_create_placeholder(self, placeholder): + """Create placeholder is going to create matching publishabe instance. + + Args: + placeholder (PlaceholderItem): Placeholder item with information + about requested publishable instance. + """ + creator_name = placeholder.data["creator"] + create_variant = placeholder.data["create_variant"] + + creator_plugin = get_legacy_creator_by_name(creator_name) + + # create subset name + project_name = legacy_io.Session["AVALON_PROJECT"] + task_name = legacy_io.Session["AVALON_TASK"] + asset_name = legacy_io.Session["AVALON_ASSET"] + + # get asset id + asset_doc = get_asset_by_name(project_name, asset_name, fields=["_id"]) + assert asset_doc, "No current asset found in Session" + asset_id = asset_doc['_id'] + + subset_name = creator_plugin.get_subset_name( + create_variant, + task_name, + asset_id, + project_name + ) + + creator_data = { + "creator_name": creator_name, + "create_variant": create_variant, + "subset_name": subset_name, + "creator_plugin": creator_plugin + } + + # compile subset name from variant + try: + creator_instance = creator_plugin( + subset_name, + asset_name + ).process() + + except Exception: + failed = True + self.create_failed(placeholder, creator_data) + + else: + failed = False + self.create_succeed(placeholder, creator_instance) + + self.cleanup_placeholder(placeholder, failed) + + def create_failed(self, placeholder, creator_data): + if hasattr(placeholder, "create_failed"): + placeholder.create_failed(creator_data) + + def create_succeed(self, placeholder, creator_instance): + if hasattr(placeholder, "create_succeed"): + placeholder.create_succeed(creator_instance) + + def cleanup_placeholder(self, placeholder, failed): + """Cleanup placeholder after load of single representation. + + Can be called multiple times during placeholder item populating and is + called even if loading failed. + + Args: + placeholder (PlaceholderItem): Item which was just used to load + representation. + failed (bool): Loading of representation failed. + """ + + pass + + class LoadPlaceholderItem(PlaceholderItem): """PlaceholderItem for plugin which is loading representations. @@ -1486,3 +1648,28 @@ class LoadPlaceholderItem(PlaceholderItem): def load_failed(self, representation): self._failed_representations.append(representation) + + +class CreatePlaceholderItem(PlaceholderItem): + """PlaceholderItem for plugin which is creating publish instance. + + Connected to 'PlaceholderCreateMixin'. + """ + + def __init__(self, *args, **kwargs): + super(CreatePlaceholderItem, self).__init__(*args, **kwargs) + self._failed_created_publish_instances = [] + + def get_errors(self): + if not self._failed_representations: + return [] + message = ( + "Failed to create {} instance using Creator {}" + ).format( + len(self._failed_created_publish_instances), + self.data["creator"] + ) + return [message] + + def create_failed(self, creator_data): + self._failed_created_publish_instances.append(creator_data) From dfb3d142aa765e27a4fc2eb3c861e70ad57fb464 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 12:17:27 +0100 Subject: [PATCH 151/211] nuke: workfile builder template creator plugin implementation --- .../nuke/api/workfile_template_builder.py | 410 +++++++++++++++++- 1 file changed, 409 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 60bf906fbe..5e9e5fcdce 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -7,7 +7,9 @@ from openpype.pipeline.workfile.workfile_template_builder import ( AbstractTemplateBuilder, PlaceholderPlugin, LoadPlaceholderItem, + CreatePlaceholderItem, PlaceholderLoadMixin, + PlaceholderCreateMixin ) from openpype.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, @@ -32,7 +34,7 @@ PLACEHOLDER_SET = "PLACEHOLDERS_SET" class NukeTemplateBuilder(AbstractTemplateBuilder): - """Concrete implementation of AbstractTemplateBuilder for maya""" + """Concrete implementation of AbstractTemplateBuilder for nuke""" def import_template(self, path): """Import template into current scene. @@ -544,6 +546,412 @@ class NukePlaceholderLoadPlugin(NukePlaceholderPlugin, PlaceholderLoadMixin): siblings_input.setInput(0, copy_output) +class NukePlaceholderCreatePlugin( + NukePlaceholderPlugin, PlaceholderCreateMixin +): + identifier = "nuke.create" + label = "Nuke create" + + def _parse_placeholder_node_data(self, node): + placeholder_data = super( + NukePlaceholderCreatePlugin, self + )._parse_placeholder_node_data(node) + + node_knobs = node.knobs() + nb_children = 0 + if "nb_children" in node_knobs: + nb_children = int(node_knobs["nb_children"].getValue()) + placeholder_data["nb_children"] = nb_children + + siblings = [] + if "siblings" in node_knobs: + siblings = node_knobs["siblings"].values() + placeholder_data["siblings"] = siblings + + node_full_name = node.fullName() + placeholder_data["group_name"] = node_full_name.rpartition(".")[0] + placeholder_data["last_loaded"] = [] + placeholder_data["delete"] = False + return placeholder_data + + def collect_placeholders(self): + output = [] + scene_placeholders = self._collect_scene_placeholders() + for node_name, node in scene_placeholders.items(): + plugin_identifier_knob = node.knob("plugin_identifier") + if ( + plugin_identifier_knob is None + or plugin_identifier_knob.getValue() != self.identifier + ): + continue + + placeholder_data = self._parse_placeholder_node_data(node) + # TODO do data validations and maybe updgrades if are invalid + output.append( + CreatePlaceholderItem(node_name, placeholder_data, self) + ) + + return output + + def populate_placeholder(self, placeholder): + self.populate_create_placeholder(placeholder) + + def repopulate_placeholder(self, placeholder): + self.populate_create_placeholder(placeholder) + + def get_placeholder_options(self, options=None): + return self.get_create_plugin_options(options) + + def cleanup_placeholder(self, placeholder, failed): + # deselect all selected nodes + placeholder_node = nuke.toNode(placeholder.scene_identifier) + + # getting the latest nodes added + nodes_init = placeholder.data["nodes_init"] + nodes_created = list(set(nuke.allNodes()) - set(nodes_init)) + self.log.debug("Created nodes: {}".format(nodes_created)) + if not nodes_created: + return + + placeholder.data["delete"] = True + + nodes_created = self._move_to_placeholder_group( + placeholder, nodes_created + ) + placeholder.data["last_created"] = nodes_created + refresh_nodes(nodes_created) + + # positioning of the created nodes + min_x, min_y, _, _ = get_extreme_positions(nodes_created) + for node in nodes_created: + xpos = (node.xpos() - min_x) + placeholder_node.xpos() + ypos = (node.ypos() - min_y) + placeholder_node.ypos() + node.setXYpos(xpos, ypos) + refresh_nodes(nodes_created) + + # fix the problem of z_order for backdrops + self._fix_z_order(placeholder) + self._imprint_siblings(placeholder) + + if placeholder.data["nb_children"] == 0: + # save initial nodes postions and dimensions, update them + # and set inputs and outputs of created nodes + + self._imprint_inits() + self._update_nodes(placeholder, nuke.allNodes(), nodes_created) + self._set_created_connections(placeholder) + + elif placeholder.data["siblings"]: + # create copies of placeholder siblings for the new created nodes, + # set their inputs and outpus and update all nodes positions and + # dimensions and siblings names + + siblings = get_nodes_by_names(placeholder.data["siblings"]) + refresh_nodes(siblings) + copies = self._create_sib_copies(placeholder) + new_nodes = list(copies.values()) # copies nodes + self._update_nodes(new_nodes, nodes_created) + placeholder_node.removeKnob(placeholder_node.knob("siblings")) + new_nodes_name = get_names_from_nodes(new_nodes) + imprint(placeholder_node, {"siblings": new_nodes_name}) + self._set_copies_connections(placeholder, copies) + + self._update_nodes( + nuke.allNodes(), + new_nodes + nodes_created, + 20 + ) + + new_siblings = get_names_from_nodes(new_nodes) + placeholder.data["siblings"] = new_siblings + + else: + # if the placeholder doesn't have siblings, the created + # nodes will be placed in a free space + + xpointer, ypointer = find_free_space_to_paste_nodes( + nodes_created, direction="bottom", offset=200 + ) + node = nuke.createNode("NoOp") + reset_selection() + nuke.delete(node) + for node in nodes_created: + xpos = (node.xpos() - min_x) + xpointer + ypos = (node.ypos() - min_y) + ypointer + node.setXYpos(xpos, ypos) + + placeholder.data["nb_children"] += 1 + reset_selection() + + # remove placeholders marked as delete + if ( + placeholder.data.get("delete") + and not placeholder.data.get("keep_placeholder") + ): + self.log.debug("Deleting node: {}".format(placeholder_node.name())) + nuke.delete(placeholder_node) + + # go back to root group + nuke.root().begin() + + def _move_to_placeholder_group(self, placeholder, nodes_created): + """ + opening the placeholder's group and copying created nodes in it. + + Returns : + nodes_created (list): the new list of pasted nodes + """ + groups_name = placeholder.data["group_name"] + reset_selection() + select_nodes(nodes_created) + if groups_name: + with node_tempfile() as filepath: + nuke.nodeCopy(filepath) + for node in nuke.selectedNodes(): + nuke.delete(node) + group = nuke.toNode(groups_name) + group.begin() + nuke.nodePaste(filepath) + nodes_created = nuke.selectedNodes() + return nodes_created + + def _fix_z_order(self, placeholder): + """Fix the problem of z_order when a backdrop is create.""" + + nodes_created = placeholder.data["last_created"] + created_backdrops = [] + bd_orders = set() + for node in nodes_created: + if isinstance(node, nuke.BackdropNode): + created_backdrops.append(node) + bd_orders.add(node.knob("z_order").getValue()) + + if not bd_orders: + return + + sib_orders = set() + for node_name in placeholder.data["siblings"]: + node = nuke.toNode(node_name) + if isinstance(node, nuke.BackdropNode): + sib_orders.add(node.knob("z_order").getValue()) + + if not sib_orders: + return + + min_order = min(bd_orders) + max_order = max(sib_orders) + for backdrop_node in created_backdrops: + z_order = backdrop_node.knob("z_order").getValue() + backdrop_node.knob("z_order").setValue( + z_order + max_order - min_order + 1) + + def _imprint_siblings(self, placeholder): + """ + - add siblings names to placeholder attributes (nodes created with it) + - add Id to the attributes of all the other nodes + """ + + created_nodes = placeholder.data["last_created"] + created_nodes_set = set(created_nodes) + data = {"repre_id": str(placeholder.data["last_repre_id"])} + + for node in created_nodes: + node_knobs = node.knobs() + if "builder_type" not in node_knobs: + # save the id of representation for all imported nodes + imprint(node, data) + node.knob("repre_id").setVisible(False) + refresh_node(node) + continue + + if ( + "is_placeholder" not in node_knobs + or ( + "is_placeholder" in node_knobs + and node.knob("is_placeholder").value() + ) + ): + siblings = list(created_nodes_set - {node}) + siblings_name = get_names_from_nodes(siblings) + siblings = {"siblings": siblings_name} + imprint(node, siblings) + + def _imprint_inits(self): + """Add initial positions and dimensions to the attributes""" + + for node in nuke.allNodes(): + refresh_node(node) + imprint(node, {"x_init": node.xpos(), "y_init": node.ypos()}) + node.knob("x_init").setVisible(False) + node.knob("y_init").setVisible(False) + width = node.screenWidth() + height = node.screenHeight() + if "bdwidth" in node.knobs(): + imprint(node, {"w_init": width, "h_init": height}) + node.knob("w_init").setVisible(False) + node.knob("h_init").setVisible(False) + refresh_node(node) + + def _update_nodes( + self, placeholder, nodes, considered_nodes, offset_y=None + ): + """Adjust backdrop nodes dimensions and positions. + + Considering some nodes sizes. + + Args: + nodes (list): list of nodes to update + considered_nodes (list): list of nodes to consider while updating + positions and dimensions + offset (int): distance between copies + """ + + placeholder_node = nuke.toNode(placeholder.scene_identifier) + + min_x, min_y, max_x, max_y = get_extreme_positions(considered_nodes) + + diff_x = diff_y = 0 + contained_nodes = [] # for backdrops + + if offset_y is None: + width_ph = placeholder_node.screenWidth() + height_ph = placeholder_node.screenHeight() + diff_y = max_y - min_y - height_ph + diff_x = max_x - min_x - width_ph + contained_nodes = [placeholder_node] + min_x = placeholder_node.xpos() + min_y = placeholder_node.ypos() + else: + siblings = get_nodes_by_names(placeholder.data["siblings"]) + minX, _, maxX, _ = get_extreme_positions(siblings) + diff_y = max_y - min_y + 20 + diff_x = abs(max_x - min_x - maxX + minX) + contained_nodes = considered_nodes + + if diff_y <= 0 and diff_x <= 0: + return + + for node in nodes: + refresh_node(node) + + if ( + node == placeholder_node + or node in considered_nodes + ): + continue + + if ( + not isinstance(node, nuke.BackdropNode) + or ( + isinstance(node, nuke.BackdropNode) + and not set(contained_nodes) <= set(node.getNodes()) + ) + ): + if offset_y is None and node.xpos() >= min_x: + node.setXpos(node.xpos() + diff_x) + + if node.ypos() >= min_y: + node.setYpos(node.ypos() + diff_y) + + else: + width = node.screenWidth() + height = node.screenHeight() + node.knob("bdwidth").setValue(width + diff_x) + node.knob("bdheight").setValue(height + diff_y) + + refresh_node(node) + + def _set_created_connections(self, placeholder): + """ + set inputs and outputs of created nodes""" + + placeholder_node = nuke.toNode(placeholder.scene_identifier) + input_node, output_node = get_group_io_nodes( + placeholder.data["last_created"] + ) + for node in placeholder_node.dependent(): + for idx in range(node.inputs()): + if node.input(idx) == placeholder_node and output_node: + node.setInput(idx, output_node) + + for node in placeholder_node.dependencies(): + for idx in range(placeholder_node.inputs()): + if placeholder_node.input(idx) == node and input_node: + input_node.setInput(0, node) + + def _create_sib_copies(self, placeholder): + """ creating copies of the palce_holder siblings (the ones who were + created with it) for the new nodes added + + Returns : + copies (dict) : with copied nodes names and their copies + """ + + copies = {} + siblings = get_nodes_by_names(placeholder.data["siblings"]) + for node in siblings: + new_node = duplicate_node(node) + + x_init = int(new_node.knob("x_init").getValue()) + y_init = int(new_node.knob("y_init").getValue()) + new_node.setXYpos(x_init, y_init) + if isinstance(new_node, nuke.BackdropNode): + w_init = new_node.knob("w_init").getValue() + h_init = new_node.knob("h_init").getValue() + new_node.knob("bdwidth").setValue(w_init) + new_node.knob("bdheight").setValue(h_init) + refresh_node(node) + + if "repre_id" in node.knobs().keys(): + node.removeKnob(node.knob("repre_id")) + copies[node.name()] = new_node + return copies + + def _set_copies_connections(self, placeholder, copies): + """Set inputs and outputs of the copies. + + Args: + copies (dict): Copied nodes by their names. + """ + + last_input, last_output = get_group_io_nodes( + placeholder.data["last_created"] + ) + siblings = get_nodes_by_names(placeholder.data["siblings"]) + siblings_input, siblings_output = get_group_io_nodes(siblings) + copy_input = copies[siblings_input.name()] + copy_output = copies[siblings_output.name()] + + for node_init in siblings: + if node_init == siblings_output: + continue + + node_copy = copies[node_init.name()] + for node in node_init.dependent(): + for idx in range(node.inputs()): + if node.input(idx) != node_init: + continue + + if node in siblings: + copies[node.name()].setInput(idx, node_copy) + else: + last_input.setInput(0, node_copy) + + for node in node_init.dependencies(): + for idx in range(node_init.inputs()): + if node_init.input(idx) != node: + continue + + if node_init == siblings_input: + copy_input.setInput(idx, node) + elif node in siblings: + node_copy.setInput(idx, copies[node.name()]) + else: + node_copy.setInput(idx, last_output) + + siblings_input.setInput(0, copy_output) + + def build_workfile_template(*args): builder = NukeTemplateBuilder(registered_host()) builder.build_template() From 013ee5660af7dcb2b88499edf8d4d6dfcf3a259c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 12:17:39 +0100 Subject: [PATCH 152/211] fix typo --- openpype/hosts/nuke/plugins/load/load_backdrop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/load/load_backdrop.py b/openpype/hosts/nuke/plugins/load/load_backdrop.py index 164ab6f9f4..d1fb763500 100644 --- a/openpype/hosts/nuke/plugins/load/load_backdrop.py +++ b/openpype/hosts/nuke/plugins/load/load_backdrop.py @@ -28,7 +28,7 @@ class LoadBackdropNodes(load.LoaderPlugin): representations = ["nk"] families = ["workfile", "nukenodes"] - label = "Iport Nuke Nodes" + label = "Import Nuke Nodes" order = 0 icon = "eye" color = "white" From 410ed90cb33348ee38525a3045612ef2a19f1970 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 12:17:54 +0100 Subject: [PATCH 153/211] fix typo --- openpype/pipeline/create/creator_plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/create/creator_plugins.py b/openpype/pipeline/create/creator_plugins.py index bb5ce00452..8500dd1e22 100644 --- a/openpype/pipeline/create/creator_plugins.py +++ b/openpype/pipeline/create/creator_plugins.py @@ -608,7 +608,7 @@ def discover_legacy_creator_plugins(): plugin.apply_settings(project_settings, system_settings) except Exception: log.warning( - "Failed to apply settings to loader {}".format( + "Failed to apply settings to creator {}".format( plugin.__name__ ), exc_info=True From ae709afaaf85ca6bd1d6d74476ea8c561d550eec Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 23 Dec 2022 12:25:01 +0100 Subject: [PATCH 154/211] Added dynamic message to Slack notification Artist can now add additional message, specific per instance and publish, if they are using Publisher. --- .../plugins/publish/collect_slack_family.py | 23 +++++++++++++++++-- .../plugins/publish/integrate_slack_api.py | 11 +++++---- website/docs/module_slack.md | 6 +++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/collect_slack_family.py b/openpype/modules/slack/plugins/publish/collect_slack_family.py index 27e899d59a..b3e7bbdcec 100644 --- a/openpype/modules/slack/plugins/publish/collect_slack_family.py +++ b/openpype/modules/slack/plugins/publish/collect_slack_family.py @@ -1,10 +1,12 @@ import pyblish.api from openpype.lib.profiles_filtering import filter_profiles -from openpype.pipeline import legacy_io +from openpype.lib import attribute_definitions +from openpype.pipeline import OpenPypePyblishPluginMixin -class CollectSlackFamilies(pyblish.api.InstancePlugin): +class CollectSlackFamilies(pyblish.api.InstancePlugin, + OpenPypePyblishPluginMixin): """Collect family for Slack notification Expects configured profile in @@ -17,6 +19,18 @@ class CollectSlackFamilies(pyblish.api.InstancePlugin): profiles = None + @classmethod + def get_attribute_defs(cls): + return [ + attribute_definitions.TextDef( + # Key under which it will be stored + "additional_message", + # Use plugin label as label for attribute + label="Additional Slack message", + placeholder="" + ) + ] + def process(self, instance): task_data = instance.data["anatomyData"].get("task", {}) family = self.main_family_from_instance(instance) @@ -55,6 +69,11 @@ class CollectSlackFamilies(pyblish.api.InstancePlugin): ["token"]) instance.data["slack_token"] = slack_token + attribute_values = self.get_attr_values_from_data(instance.data) + additional_message = attribute_values.get("additional_message") + if additional_message: + instance.data["slack_additional_message"] = additional_message + def main_family_from_instance(self, instance): # TODO yank from integrate """Returns main family of entered instance.""" family = instance.data.get("family") diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 0cd5ec9de8..d94ecb02e4 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -31,11 +31,14 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): review_path = self._get_review_path(instance) publish_files = set() + message = '' + additional_message = instance.data.get("slack_additional_message") + if additional_message: + message = "{} \n".format(additional_message) for message_profile in instance.data["slack_channel_message_profiles"]: - message = self._get_filled_message(message_profile["message"], - instance, - review_path) - self.log.debug("message:: {}".format(message)) + message += self._get_filled_message(message_profile["message"], + instance, + review_path) if not message: return diff --git a/website/docs/module_slack.md b/website/docs/module_slack.md index 3a2842da63..2bfd7cb562 100644 --- a/website/docs/module_slack.md +++ b/website/docs/module_slack.md @@ -94,6 +94,12 @@ Few keys also have Capitalized and UPPERCASE format. Values will be modified acc Here you can find review {review_filepath} ``` +##### Dynamic message for artists +If artists uses host with implemented Publisher (new UI for publishing, implemented in Tray Publisher, Adobe products etc), it is possible for +them to add additional message (notification for specific users for example, artists must provide proper user id with '@'). +Additional message will be sent only if at least one profile, eg. one target channel is configured. +All available template keys (see higher) could be used here as a placeholder too. + #### Message retention Currently no purging of old messages is implemented in Openpype. Admins of Slack should set their own retention of messages and files per channel. (see https://slack.com/help/articles/203457187-Customize-message-and-file-retention-policies) From c6c08fd4ccaf779c2569139ab83f8fb16fe6c785 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 12:46:14 +0100 Subject: [PATCH 155/211] global: fix creator plugin discovery --- .../pipeline/workfile/workfile_template_builder.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index d85d6b50dd..07a1f3ec58 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -238,7 +238,14 @@ class AbstractTemplateBuilder(object): def get_creators_by_name(self): if self._creators_by_name is None: - self._creators_by_name = discover_legacy_creator_plugins() + self._creators_by_name = {} + for creator in discover_legacy_creator_plugins(): + creator_name = creator.__name__ + if creator_name in self._creators_by_name: + raise KeyError( + "Duplicated creator name {} !".format(creator_name) + ) + self._creators_by_name[creator_name] = creator return self._creators_by_name def get_shared_data(self, key): @@ -1497,6 +1504,8 @@ class PlaceholderCreateMixin(object): """ creators_by_name = self.builder.get_creators_by_name() + print(creators_by_name) + creator_items = [ (creator_name, creator.label or creator_name) for creator_name, creator in creators_by_name.items() From c16a5289e49286bb7c65be04a9629f846cab58ce Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 23 Dec 2022 14:09:03 +0100 Subject: [PATCH 156/211] OP-4470 - better handle missing keys Message might contain {placeholder} which are not collected. Previously it would fail without sending message. Now missing keys are double escaped {{}}. --- .../plugins/publish/integrate_slack_api.py | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 0cd5ec9de8..9122c1c5ed 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -1,4 +1,5 @@ import os +import re import six import pyblish.api import copy @@ -132,14 +133,14 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): fill_key = "task[{}]".format(key) fill_pairs.append((fill_key, value)) - self.log.debug("fill_pairs ::{}".format(fill_pairs)) multiple_case_variants = prepare_template_data(fill_pairs) fill_data.update(multiple_case_variants) - - message = None + message = '' try: - message = message_templ.format(**fill_data) + message = self._escape_missing_keys(message_templ, fill_data).\ + format(**fill_data) except Exception: + # shouldn't happen self.log.warning( "Some keys are missing in {}".format(message_templ), exc_info=True) @@ -263,3 +264,22 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): msg = " - application must added to channel '{}'.".format(channel) error_str += msg + " Ask Slack admin." return error_str + + def _escape_missing_keys(self, message, fill_data): + """Double escapes placeholder which are missing in 'fill_data'""" + placeholder_keys = re.findall("\{([^}]+)\}", message) + + fill_keys = [] + for key, value in fill_data.items(): + fill_keys.append(key) + if isinstance(value, dict): + for child_key in value.keys(): + fill_keys.append("{}[{}]".format(key, child_key)) + + not_matched = set(placeholder_keys) - set(fill_keys) + + for not_matched_item in not_matched: + message = message.replace("{}".format(not_matched_item), + "{{{}}}".format(not_matched_item)) + + return message From 3a41d6a72158af0707d58f146b834076ed386b13 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 23 Dec 2022 14:13:00 +0100 Subject: [PATCH 157/211] OP-4470 - safer handling of review path 'published_path' might be missing. Thumbnail path was fixed previously, this one was missed. --- .../slack/plugins/publish/integrate_slack_api.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 9122c1c5ed..c4d6b27726 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -163,17 +163,21 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): def _get_review_path(self, instance): """Returns abs url for review if present in instance repres""" - published_path = None + review_path = None for repre in instance.data.get("representations", []): tags = repre.get('tags', []) if (repre.get("review") or "review" in tags or "burnin" in tags): - if os.path.exists(repre["published_path"]): - published_path = repre["published_path"] + repre_review_path = ( + repre.get("published_path") or + os.path.join(repre["stagingDir"], repre["files"]) + ) + if os.path.exists(repre_review_path): + review_path = repre_review_path if "burnin" in tags: # burnin has precedence if exists break - return published_path + return review_path def _python2_call(self, token, channel, message, publish_files): from slackclient import SlackClient From 81de2cf0c902671104de22f7768ed37ac8ed5c39 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 14:25:41 +0100 Subject: [PATCH 158/211] global: fix _repr_ pformat printing --- openpype/pipeline/workfile/workfile_template_builder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 07a1f3ec58..630a11e4b5 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -984,7 +984,7 @@ class PlaceholderItem(object): def __init__(self, scene_identifier, data, plugin): self._log = None - self._scene_identifier = scene_identifier + self.name = scene_identifier self._data = data self._plugin = plugin @@ -1062,7 +1062,7 @@ class PlaceholderItem(object): @property def scene_identifier(self): - return self._scene_identifier + return self.name @property def finished(self): From 4f7e4fcac3ffbddc258247941b063f25746ef174 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 14:26:28 +0100 Subject: [PATCH 159/211] global: add _before_instance_create function for storing created nodes --- openpype/pipeline/workfile/workfile_template_builder.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 630a11e4b5..dce36eca82 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1594,6 +1594,8 @@ class PlaceholderCreateMixin(object): "creator_plugin": creator_plugin } + self._before_instance_create(placeholder) + # compile subset name from variant try: creator_instance = creator_plugin( @@ -1633,6 +1635,11 @@ class PlaceholderCreateMixin(object): pass + def _before_instance_create(self, placeholder): + """Can be overriden. Is called before instance is created.""" + + pass + class LoadPlaceholderItem(PlaceholderItem): """PlaceholderItem for plugin which is loading representations. From 5924dcc1f5d80b532fa30137cf1992b89d71d092 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 14:27:32 +0100 Subject: [PATCH 160/211] nuke: implementing _before_instance_create funtion --- openpype/hosts/nuke/api/workfile_template_builder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 5e9e5fcdce..33dcdab749 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -574,6 +574,9 @@ class NukePlaceholderCreatePlugin( placeholder_data["delete"] = False return placeholder_data + def _before_instance_create(self, placeholder): + placeholder.data["nodes_init"] = nuke.allNodes() + def collect_placeholders(self): output = [] scene_placeholders = self._collect_scene_placeholders() From c06315d5d6d2ce567e152f25600b23fc2b7c2b47 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 14:28:03 +0100 Subject: [PATCH 161/211] nuke: fixing logic for creator placeholder plugin processing --- openpype/hosts/nuke/api/workfile_template_builder.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 33dcdab749..973e15b192 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -76,8 +76,7 @@ class NukePlaceholderPlugin(PlaceholderPlugin): node_knobs = node.knobs() if ( - "builder_type" not in node_knobs - or "is_placeholder" not in node_knobs + "is_placeholder" not in node_knobs or not node.knob("is_placeholder").value() ): continue @@ -756,16 +755,9 @@ class NukePlaceholderCreatePlugin( created_nodes = placeholder.data["last_created"] created_nodes_set = set(created_nodes) - data = {"repre_id": str(placeholder.data["last_repre_id"])} for node in created_nodes: node_knobs = node.knobs() - if "builder_type" not in node_knobs: - # save the id of representation for all imported nodes - imprint(node, data) - node.knob("repre_id").setVisible(False) - refresh_node(node) - continue if ( "is_placeholder" not in node_knobs From c0157e5787a822064238847a4b2a7e5bac71970c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 23 Dec 2022 17:34:47 +0100 Subject: [PATCH 162/211] remove todo --- openpype/hosts/nuke/api/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 973e15b192..1b81f24e86 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -588,7 +588,7 @@ class NukePlaceholderCreatePlugin( continue placeholder_data = self._parse_placeholder_node_data(node) - # TODO do data validations and maybe updgrades if are invalid + output.append( CreatePlaceholderItem(node_name, placeholder_data, self) ) From 18949a0c76ecb7033867658eacbf4f05e03ff160 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 24 Dec 2022 03:27:57 +0000 Subject: [PATCH 163/211] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index 904579ad55..e14bc9daab 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.2" +__version__ = "3.14.10-nightly.3" From 8b6bc8444db044391bbe340e981abc404d1ffb38 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 28 Dec 2022 03:28:14 +0000 Subject: [PATCH 164/211] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index e14bc9daab..40abb9e9fd 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.3" +__version__ = "3.14.10-nightly.4" From f5842d91bd49cc955f49ed53388efd565b84f0a6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Dec 2022 12:18:11 +0100 Subject: [PATCH 165/211] rename variable 'max_len' to 'message_len' --- openpype/widgets/message_window.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index 94e51f5d4f..8301f5e8f2 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -105,16 +105,18 @@ class ScrollMessageBox(QtWidgets.QDialog): content_widget = QtWidgets.QWidget(self) scroll_widget.setWidget(content_widget) - max_len = 0 + message_len = 0 content_layout = QtWidgets.QVBoxLayout(content_widget) for message in messages: label_widget = QtWidgets.QLabel(message, content_widget) content_layout.addWidget(label_widget) - max_len = max(max_len, len(message)) + message_len = max(message_len, len(message)) # guess size of scrollable area max_width = QtWidgets.QApplication.desktop().availableGeometry().width - scroll_widget.setMinimumWidth(min(max_width, max_len * 6)) + scroll_widget.setMinimumWidth( + min(max_width, message_len * 6) + ) layout.addWidget(scroll_widget) if not cancelable: # if no specific buttons OK only From a941aabc049ee3ec59ef829dbd58c1abca937868 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Dec 2022 12:21:05 +0100 Subject: [PATCH 166/211] call the width method to get the value --- openpype/widgets/message_window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index 8301f5e8f2..2b186475ee 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -113,7 +113,7 @@ class ScrollMessageBox(QtWidgets.QDialog): message_len = max(message_len, len(message)) # guess size of scrollable area - max_width = QtWidgets.QApplication.desktop().availableGeometry().width + max_width = QtWidgets.QApplication.desktop().availableGeometry().width() scroll_widget.setMinimumWidth( min(max_width, message_len * 6) ) From f3c13e7669c149ef4b652820a2f72f4553484ea2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Dec 2022 12:26:25 +0100 Subject: [PATCH 167/211] fix too long line --- openpype/widgets/message_window.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index 2b186475ee..a44df2ec8e 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -113,7 +113,8 @@ class ScrollMessageBox(QtWidgets.QDialog): message_len = max(message_len, len(message)) # guess size of scrollable area - max_width = QtWidgets.QApplication.desktop().availableGeometry().width() + desktop = QtWidgets.QApplication.desktop() + max_width = desktop.availableGeometry().width() scroll_widget.setMinimumWidth( min(max_width, message_len * 6) ) From e1f040c9eaba834ae5585577c7c1b3779f0b7e3a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Dec 2022 15:05:34 +0100 Subject: [PATCH 168/211] nuke: validator exception legacy --- .../publish/help/validate_write_nodes.xml | 26 ++++++++++++++----- .../plugins/publish/validate_write_nodes.py | 21 +++++++++++++-- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/help/validate_write_nodes.xml b/openpype/hosts/nuke/plugins/publish/help/validate_write_nodes.xml index cdf85102bc..1717622a45 100644 --- a/openpype/hosts/nuke/plugins/publish/help/validate_write_nodes.xml +++ b/openpype/hosts/nuke/plugins/publish/help/validate_write_nodes.xml @@ -3,16 +3,30 @@ Knobs values -## Invalid node's knobs values + ## Invalid node's knobs values -Following write node knobs needs to be repaired: + Following write node knobs needs to be repaired: -{xml_msg} + {xml_msg} -### How to repair? + ### How to repair? -1. Use Repair button. -2. Hit Reload button on the publisher. + 1. Use Repair button. + 2. Hit Reload button on the publisher. + + + + Legacy knob types + + ## Knobs are in obsolete configuration + + Settings needs to be fixed. + + ### How to repair? + + Contact your supervisor or fix it in project settings at + 'project_settings/nuke/imageio/nodes/requiredNodes' at knobs. + Each '__legacy__' type has to be defined accordingly to its type. \ No newline at end of file diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index c0b81f64ea..9027e54fc5 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -77,14 +77,31 @@ class ValidateNukeWriteNode( if write_node is None: return - correct_data = get_write_node_template_attr(write_group_node) + check_knobs = get_write_node_template_attr(write_group_node) check = [] self.log.debug("__ write_node: {}".format( write_node )) + self.log.debug("__ check_knobs: {}".format( + check_knobs + )) - for key, value in correct_data.items(): + for knob_data in check_knobs: + if ( + "type" not in knob_data + or knob_data["type"] == "__legacy__" + ): + PublishXmlValidationError( + self, ( + "Please update data in settings 'project_settings" + "/nuke/imageio/nodes/requiredNodes'" + ), + key="legacy" + ) + + key = knob_data["name"] + value = knob_data["value"] node_value = write_node[key].value() # fix type differences From 47a31b44915a35cfdcd7a1efd8a4e2edf8256cb6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Dec 2022 15:46:44 +0100 Subject: [PATCH 169/211] nuke: write node validator check __legacy__ type --- openpype/hosts/nuke/api/lib.py | 21 +++++-------------- .../plugins/publish/validate_write_nodes.py | 18 +++++++++------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 2aa706d738..c454086985 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2371,8 +2371,8 @@ def get_write_node_template_attr(node): ''' Gets all defined data from presets ''' - # TODO: remove this backward compatibility for old settings - # TASK: add identifiers to settings and rename settings key + + # TODO: add identifiers to settings and rename settings key plugin_names_mapping = { "create_write_image": "CreateWriteImage", "create_write_prerender": "CreateWritePrerender", @@ -2381,25 +2381,14 @@ def get_write_node_template_attr(node): # get avalon data from node node_data = get_node_data(node, INSTANCE_DATA_KNOB) identifier = node_data["creator_identifier"] - # get template data - nuke_imageio_writes = get_imageio_node_setting( + + # return template data + return get_imageio_node_setting( node_class="Write", plugin_name=plugin_names_mapping[identifier], subset=node_data["subset"] ) - # collecting solved data - return_data = OrderedDict() - - for knob in nuke_imageio_writes["knobs"]: - knob_type = knob["type"] - knob_value = knob["value"] - new_knob_value = convert_knob_value_to_correct_type( - knob_type, knob_value) - return_data[knob["name"]] = new_knob_value - - return return_data - def get_dependent_nodes(nodes): """Get all dependent nodes connected to the list of nodes. diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 9027e54fc5..aeecea655f 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -77,22 +77,26 @@ class ValidateNukeWriteNode( if write_node is None: return - check_knobs = get_write_node_template_attr(write_group_node) + correct_data = get_write_node_template_attr(write_group_node) check = [] self.log.debug("__ write_node: {}".format( write_node )) - self.log.debug("__ check_knobs: {}".format( - check_knobs + self.log.debug("__ correct_data: {}".format( + correct_data )) - for knob_data in check_knobs: + for knob_data in correct_data["knobs"]: + knob_type = knob_data["type"] + self.log.debug("__ knob_type: {}".format( + knob_type + )) + if ( - "type" not in knob_data - or knob_data["type"] == "__legacy__" + knob_type == "__legacy__" ): - PublishXmlValidationError( + raise PublishXmlValidationError( self, ( "Please update data in settings 'project_settings" "/nuke/imageio/nodes/requiredNodes'" From efab124e0f721e03367710f1800bb6b0a8f9ca1e Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 31 Dec 2022 03:27:31 +0000 Subject: [PATCH 170/211] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index 40abb9e9fd..4fbe5a3608 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.4" +__version__ = "3.14.10-nightly.5" From 7a372d1b1cd481610a044a552e155db62ae8adbb Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 3 Jan 2023 17:05:47 +0100 Subject: [PATCH 171/211] Added possibility to mention users or groups --- .../plugins/publish/integrate_slack_api.py | 271 ++++++++++++++---- 1 file changed, 213 insertions(+), 58 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index d94ecb02e4..8d34521194 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -3,6 +3,9 @@ import six import pyblish.api import copy from datetime import datetime +import re +from abc import ABCMeta, abstractmethod +import time from openpype.client import OpenPypeMongoConnection from openpype.lib.plugin_tools import prepare_template_data @@ -33,6 +36,7 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): publish_files = set() message = '' additional_message = instance.data.get("slack_additional_message") + token = instance.data["slack_token"] if additional_message: message = "{} \n".format(additional_message) for message_profile in instance.data["slack_channel_message_profiles"]: @@ -52,18 +56,16 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): project = instance.context.data["anatomyData"]["project"]["code"] for channel in message_profile["channels"]: if six.PY2: - msg_id, file_ids = \ - self._python2_call(instance.data["slack_token"], - channel, - message, - publish_files) + client = SlackPython2Operations(token, self.log) else: - msg_id, file_ids = \ - self._python3_call(instance.data["slack_token"], - channel, - message, - publish_files) + client = SlackPython3Operations(token, self.log) + users, groups = client.get_users_and_groups() + message = self._translate_users(message, users, groups) + + msg_id, file_ids = client.send_message(channel, + message, + publish_files) if not msg_id: return @@ -177,15 +179,211 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): break return published_path - def _python2_call(self, token, channel, message, publish_files): - from slackclient import SlackClient + def _get_user_id(self, users, user_name): + """Returns internal slack id for user name""" + user_id = None + for user in users: + if (not user.get("deleted") and + (user_name.lower() == user["name"].lower() or + user_name.lower() == user["real_name"])): + user_id = user["id"] + break + return user_id + + def _get_group_id(self, groups, group_name): + """Returns internal group id for string name""" + group_id = None + for group in groups: + if (not group.get("date_delete") and + (group_name.lower() == group["name"].lower() or + group_name.lower() == group["handle"])): + group_id = group["id"] + break + return group_id + + def _translate_users(self, message, users, groups): + matches = re.findall("(?".format(slack_id) + else: + slack_id = self._get_group_id(groups, user_name) + if slack_id: + mention = "".format(slack_id) + if mention: + message = message.replace(orig_user, mention) + + return message + + +@six.add_metaclass(ABCMeta) +class AbstractSlackOperations: + + @abstractmethod + def _get_users_list(self): + """Return response with user list, different methods Python 2 vs 3""" + raise NotImplementedError + + @abstractmethod + def _get_usergroups_list(self): + """Return response with user list, different methods Python 2 vs 3""" + raise NotImplementedError + + @abstractmethod + def get_users_and_groups(self): + """Return users and groups, different retry in Python 2 vs 3""" + raise NotImplementedError + + @abstractmethod + def send_message(self, channel, message, publish_files): + """Sends message to channel, different methods in Python 2 vs 3""" + pass + + def _get_users(self): + """Parse users.list response into list of users (dicts)""" + first = True + next_page = None + users = [] + while first or next_page: + response = self._get_users_list() + first = False + next_page = response.get("response_metadata").get("next_cursor") + for user in response.get("members"): + users.append(user) + + return users + + def _get_groups(self): + """Parses usergroups.list response into list of groups (dicts)""" + response = self._get_usergroups_list() + groups = [] + for group in response.get("usergroups"): + groups.append(group) + return groups + + def _enrich_error(self, error_str, channel): + """Enhance known errors with more helpful notations.""" + if 'not_in_channel' in error_str: + # there is no file.write.public scope, app must be explicitly in + # the channel + msg = " - application must added to channel '{}'.".format(channel) + error_str += msg + " Ask Slack admin." + return error_str + + +class SlackPython3Operations(AbstractSlackOperations): + + def __init__(self, token, log): + from slack_sdk import WebClient + + self.client = WebClient(token=token) + self.log = log + + def _get_users_list(self): + return self.client.users_list() + + def _get_usergroups_list(self): + return self.client.usergroups_list() + + def get_users_and_groups(self): + from slack_sdk.errors import SlackApiError + while True: + try: + users = self._get_users() + groups = self._get_groups() + break + except SlackApiError as e: + retry_after = e.response.headers.get("Retry-After") + if retry_after: + print( + "Rate limit hit, sleeping for {}".format(retry_after)) + time.sleep(int(retry_after)) + else: + raise e + + return users, groups + + def send_message(self, channel, message, publish_files): + from slack_sdk.errors import SlackApiError + try: + attachment_str = "\n\n Attachment links: \n" + file_ids = [] + for published_file in publish_files: + response = self.client.files_upload( + file=published_file, + filename=os.path.basename(published_file)) + attachment_str += "\n<{}|{}>".format( + response["file"]["permalink"], + os.path.basename(published_file)) + file_ids.append(response["file"]["id"]) + + if publish_files: + message += attachment_str + + message = self.translate_users(message) + + response = self.client.chat_postMessage( + channel=channel, + text=message + ) + return response.data["ts"], file_ids + except SlackApiError as e: + # # You will get a SlackApiError if "ok" is False + error_str = self._enrich_error(str(e.response["error"]), channel) + self.log.warning("Error happened {}".format(error_str)) + except Exception as e: + error_str = self._enrich_error(str(e), channel) + self.log.warning("Not SlackAPI error", exc_info=True) + + return None, [] + + +class SlackPython2Operations(AbstractSlackOperations): + + def __init__(self, token, log): + from slackclient import SlackClient + + self.client = SlackClient(token=token) + self.log = log + + def _get_users_list(self): + return self.client.api_call("users.list") + + def _get_usergroups_list(self): + return self.client.api_call("usergroups.list") + + def get_users_and_groups(self): + while True: + try: + users = self._get_users() + groups = self._get_groups() + break + except Exception as e: + retry_after = e.response.headers.get("Retry-After") + if retry_after: + print( + "Rate limit hit, sleeping for {}".format(retry_after)) + time.sleep(int(retry_after)) + else: + raise e + + return users, groups + + def send_message(self, channel, message, publish_files): try: - client = SlackClient(token) attachment_str = "\n\n Attachment links: \n" file_ids = [] for p_file in publish_files: with open(p_file, 'rb') as pf: - response = client.api_call( + response = self.client.api_call( "files.upload", file=pf, channel=channel, @@ -206,7 +404,7 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): if publish_files: message += attachment_str - response = client.api_call( + response = self.client.api_call( "chat.postMessage", channel=channel, text=message @@ -223,46 +421,3 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): self.log.warning("Error happened: {}".format(error_str)) return None, [] - - def _python3_call(self, token, channel, message, publish_files): - from slack_sdk import WebClient - from slack_sdk.errors import SlackApiError - try: - client = WebClient(token=token) - attachment_str = "\n\n Attachment links: \n" - file_ids = [] - for published_file in publish_files: - response = client.files_upload( - file=published_file, - filename=os.path.basename(published_file)) - attachment_str += "\n<{}|{}>".format( - response["file"]["permalink"], - os.path.basename(published_file)) - file_ids.append(response["file"]["id"]) - - if publish_files: - message += attachment_str - - response = client.chat_postMessage( - channel=channel, - text=message - ) - return response.data["ts"], file_ids - except SlackApiError as e: - # You will get a SlackApiError if "ok" is False - error_str = self._enrich_error(str(e.response["error"]), channel) - self.log.warning("Error happened {}".format(error_str)) - except Exception as e: - error_str = self._enrich_error(str(e), channel) - self.log.warning("Not SlackAPI error", exc_info=True) - - return None, [] - - def _enrich_error(self, error_str, channel): - """Enhance known errors with more helpful notations.""" - if 'not_in_channel' in error_str: - # there is no file.write.public scope, app must be explicitly in - # the channel - msg = " - application must added to channel '{}'.".format(channel) - error_str += msg + " Ask Slack admin." - return error_str From 1ee50975c0e61acac51f7f76b905a420e95487c6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 3 Jan 2023 17:14:41 +0100 Subject: [PATCH 172/211] Fix wrong position of method --- .../plugins/publish/integrate_slack_api.py | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index a010d08a82..fc5342177d 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -228,6 +228,25 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): return message + def _escape_missing_keys(self, message, fill_data): + """Double escapes placeholder which are missing in 'fill_data'""" + placeholder_keys = re.findall("\{([^}]+)\}", message) + + fill_keys = [] + for key, value in fill_data.items(): + fill_keys.append(key) + if isinstance(value, dict): + for child_key in value.keys(): + fill_keys.append("{}[{}]".format(key, child_key)) + + not_matched = set(placeholder_keys) - set(fill_keys) + + for not_matched_item in not_matched: + message = message.replace("{}".format(not_matched_item), + "{{{}}}".format(not_matched_item)) + + return message + @six.add_metaclass(ABCMeta) class AbstractSlackOperations: @@ -283,25 +302,6 @@ class AbstractSlackOperations: error_str += msg + " Ask Slack admin." return error_str - def _escape_missing_keys(self, message, fill_data): - """Double escapes placeholder which are missing in 'fill_data'""" - placeholder_keys = re.findall("\{([^}]+)\}", message) - - fill_keys = [] - for key, value in fill_data.items(): - fill_keys.append(key) - if isinstance(value, dict): - for child_key in value.keys(): - fill_keys.append("{}[{}]".format(key, child_key)) - - not_matched = set(placeholder_keys) - set(fill_keys) - - for not_matched_item in not_matched: - message = message.replace("{}".format(not_matched_item), - "{{{}}}".format(not_matched_item)) - - return message - class SlackPython3Operations(AbstractSlackOperations): From f80fe3fb938488009974cd931b285ea8564d7b2b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 3 Jan 2023 17:14:57 +0100 Subject: [PATCH 173/211] Fix obsolete call of method --- openpype/modules/slack/plugins/publish/integrate_slack_api.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index fc5342177d..803a07f5d2 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -352,8 +352,6 @@ class SlackPython3Operations(AbstractSlackOperations): if publish_files: message += attachment_str - message = self.translate_users(message) - response = self.client.chat_postMessage( channel=channel, text=message From 394c678299f26967ba64b87a7c8684c1d0419191 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 3 Jan 2023 17:19:50 +0100 Subject: [PATCH 174/211] Do not throw exception if user or group list error Skip notification, publish shouldn't fail because of this. --- .../modules/slack/plugins/publish/integrate_slack_api.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 803a07f5d2..f18b927c98 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -331,7 +331,9 @@ class SlackPython3Operations(AbstractSlackOperations): "Rate limit hit, sleeping for {}".format(retry_after)) time.sleep(int(retry_after)) else: - raise e + self.log.warning("Cannot pull user info, " + "mentions won't work", exc_info=True) + return [], [] return users, groups @@ -395,7 +397,9 @@ class SlackPython2Operations(AbstractSlackOperations): "Rate limit hit, sleeping for {}".format(retry_after)) time.sleep(int(retry_after)) else: - raise e + self.log.warning("Cannot pull user info, " + "mentions won't work", exc_info=True) + return [], [] return users, groups From 61ef7479e8bbb842378229e87b2187924a368c7a Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 3 Jan 2023 17:21:14 +0100 Subject: [PATCH 175/211] =?UTF-8?q?=F0=9F=94=A7=20pass=20mongo=20url=20as?= =?UTF-8?q?=20default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/settings/defaults/project_settings/deadline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index 6e1c0f3540..527f5c0d24 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -2,7 +2,7 @@ "deadline_servers": [], "publish": { "CollectDefaultDeadlineServer": { - "pass_mongo_url": false + "pass_mongo_url": true }, "CollectDeadlinePools": { "primary_pool": "", From 68fe82323883c8035f3831820681174980649802 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 3 Jan 2023 17:53:00 +0100 Subject: [PATCH 176/211] Fix resolving of user_id Display name or real_name could be used also. --- .../slack/plugins/publish/integrate_slack_api.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index f18b927c98..577ead9667 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -187,10 +187,13 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): def _get_user_id(self, users, user_name): """Returns internal slack id for user name""" user_id = None + user_name_lower = user_name.lower() for user in users: if (not user.get("deleted") and - (user_name.lower() == user["name"].lower() or - user_name.lower() == user["real_name"])): + (user_name_lower == user["name"].lower() or + # bots dont have display_name + user_name_lower == user.get("display_name", '').lower() or + user_name_lower == user.get("real_name", '').lower())): user_id = user["id"] break return user_id @@ -208,8 +211,9 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): def _translate_users(self, message, users, groups): matches = re.findall("(? Date: Tue, 3 Jan 2023 17:58:28 +0100 Subject: [PATCH 177/211] Updated documentation --- website/docs/module_slack.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/docs/module_slack.md b/website/docs/module_slack.md index 2bfd7cb562..1999912fdc 100644 --- a/website/docs/module_slack.md +++ b/website/docs/module_slack.md @@ -100,6 +100,10 @@ them to add additional message (notification for specific users for example, art Additional message will be sent only if at least one profile, eg. one target channel is configured. All available template keys (see higher) could be used here as a placeholder too. +#### User or group notifications +Message template or dynamic data could contain user or group notification, it must be in format @artist.name, '@John Doe' or "@admin group" for display name containing space. +If value prefixed with @ is not resolved and Slack user is not found, message will contain same value (not translated by Slack into link and proper mention.) + #### Message retention Currently no purging of old messages is implemented in Openpype. Admins of Slack should set their own retention of messages and files per channel. (see https://slack.com/help/articles/203457187-Customize-message-and-file-retention-policies) From f1111a99bda950cb79ff36675f12c34146f05ddf Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 4 Jan 2023 03:28:26 +0000 Subject: [PATCH 178/211] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index 4fbe5a3608..ae514e371e 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.5" +__version__ = "3.14.10-nightly.6" From b2e8ea6fb80faeef67cbae6db212422c43cb0b58 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 4 Jan 2023 11:36:12 +0100 Subject: [PATCH 179/211] Hound --- .../modules/slack/plugins/publish/integrate_slack_api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 577ead9667..97182ffd9b 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -4,7 +4,6 @@ import six import pyblish.api import copy from datetime import datetime -import re from abc import ABCMeta, abstractmethod import time @@ -210,8 +209,9 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): return group_id def _translate_users(self, message, users, groups): - matches = re.findall("(? format.""" + matches = re.findall(r"(? Date: Wed, 4 Jan 2023 12:44:07 +0100 Subject: [PATCH 180/211] Fix - search pattern Updated to use user profile --- .../modules/slack/plugins/publish/integrate_slack_api.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 97182ffd9b..02197a6d01 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -191,8 +191,10 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): if (not user.get("deleted") and (user_name_lower == user["name"].lower() or # bots dont have display_name - user_name_lower == user.get("display_name", '').lower() or - user_name_lower == user.get("real_name", '').lower())): + user_name_lower == user["profile"].get("display_name", + '').lower() or + user_name_lower == user["profile"].get("real_name", + '').lower())): user_id = user["id"] break return user_id @@ -210,7 +212,7 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): def _translate_users(self, message, users, groups): """Replace all occurences of @mentions with proper <@name> format.""" - matches = re.findall(r"(? Date: Wed, 4 Jan 2023 12:51:47 +0100 Subject: [PATCH 181/211] Fix - cannot pull response from ordinary exception --- .../slack/plugins/publish/integrate_slack_api.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 02197a6d01..bb5cd40936 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -397,15 +397,9 @@ class SlackPython2Operations(AbstractSlackOperations): groups = self._get_groups() break except Exception as e: - retry_after = e.response.headers.get("Retry-After") - if retry_after: - print( - "Rate limit hit, sleeping for {}".format(retry_after)) - time.sleep(int(retry_after)) - else: - self.log.warning("Cannot pull user info, " - "mentions won't work", exc_info=True) - return [], [] + self.log.warning("Cannot pull user info, " + "mentions won't work", exc_info=True) + return [], [] return users, groups From dff87d4e1cfabafb4ec40c46a1cbc48c851f661f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 4 Jan 2023 12:52:32 +0100 Subject: [PATCH 182/211] Hound --- openpype/modules/slack/plugins/publish/integrate_slack_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index bb5cd40936..21069e0b13 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -396,7 +396,7 @@ class SlackPython2Operations(AbstractSlackOperations): users = self._get_users() groups = self._get_groups() break - except Exception as e: + except Exception: self.log.warning("Cannot pull user info, " "mentions won't work", exc_info=True) return [], [] From 40cf2956fd968c8ffaf47c584c69705a852e4bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Wed, 4 Jan 2023 14:26:15 +0100 Subject: [PATCH 183/211] Update openpype/pipeline/workfile/workfile_template_builder.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/pipeline/workfile/workfile_template_builder.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index dce36eca82..24b0cc81f1 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1504,7 +1504,6 @@ class PlaceholderCreateMixin(object): """ creators_by_name = self.builder.get_creators_by_name() - print(creators_by_name) creator_items = [ (creator_name, creator.label or creator_name) From e69f3539eaeac23d0663e71f83c9d463cbc50699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Wed, 4 Jan 2023 14:26:26 +0100 Subject: [PATCH 184/211] Update openpype/pipeline/workfile/workfile_template_builder.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/pipeline/workfile/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 24b0cc81f1..a834ca0e21 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -675,7 +675,7 @@ class AbstractTemplateBuilder(object): # switch to remove placeholders after they are used placeholder_keep = profile.get("placeholder_keep") # backward compatibility, since default is True - if placeholder_keep is not False: + if placeholder_keep is None: placeholder_keep = True if not path: From b01322645ae14e74b09d4125fcac5a8160d76c57 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 4 Jan 2023 14:44:04 +0100 Subject: [PATCH 185/211] Correctly repair frame range with handle attributes if `handleStart` and `handleEnd` available on instance --- .../plugins/publish/validate_frame_range.py | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_frame_range.py b/openpype/hosts/maya/plugins/publish/validate_frame_range.py index 5e50ae72cd..dec2f00700 100644 --- a/openpype/hosts/maya/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/maya/plugins/publish/validate_frame_range.py @@ -92,10 +92,31 @@ class ValidateFrameRange(pyblish.api.InstancePlugin): """ Repair instance container to match asset data. """ - cmds.setAttr( - "{}.frameStart".format(instance.data["name"]), - instance.context.data.get("frameStartHandle")) - cmds.setAttr( - "{}.frameEnd".format(instance.data["name"]), - instance.context.data.get("frameEndHandle")) + node = instance.data["name"] + context = instance.context + + frame_start_handle = int(context.data.get("frameStartHandle")) + frame_end_handle = int(context.data.get("frameEndHandle")) + handle_start = int(context.data.get("handleStart")) + handle_end = int(context.data.get("handleEnd")) + frame_start = int(context.data.get("frameStart")) + frame_end = int(context.data.get("frameEnd")) + + # Start + if cmds.attributeQuery("handleStart", node=node, exists=True): + cmds.setAttr("{}.handleStart".format(node), handle_start) + cmds.setAttr("{}.frameStart".format(node), frame_start) + else: + # Include start handle in frame start if no separate handleStart + # attribute exists on the node + cmds.setAttr("{}.frameStart".format(node), frame_start_handle) + + # End + if cmds.attributeQuery("handleEnd", node=node, exists=True): + cmds.setAttr("{}.handleEnd".format(node), handle_end) + cmds.setAttr("{}.frameEnd".format(node), frame_end) + else: + # Include end handle in frame end if no separate handleEnd + # attribute exists on the node + cmds.setAttr("{}.frameEnd".format(node), frame_end_handle) From 0a4ed0988c0a359bbec6b6929d9073215af3cdea Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 4 Jan 2023 14:45:00 +0100 Subject: [PATCH 186/211] Do not force instance handleStart and handleEnd to zero if not `handles` in data --- openpype/hosts/maya/plugins/publish/collect_instances.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_instances.py b/openpype/hosts/maya/plugins/publish/collect_instances.py index ad1f794680..75bc935143 100644 --- a/openpype/hosts/maya/plugins/publish/collect_instances.py +++ b/openpype/hosts/maya/plugins/publish/collect_instances.py @@ -174,9 +174,6 @@ class CollectInstances(pyblish.api.ContextPlugin): if "handles" in data: data["handleStart"] = data["handles"] data["handleEnd"] = data["handles"] - else: - data["handleStart"] = 0 - data["handleEnd"] = 0 data["frameStartHandle"] = data["frameStart"] - data["handleStart"] # noqa: E501 data["frameEndHandle"] = data["frameEnd"] + data["handleEnd"] # noqa: E501 From e44f585aa63c32ebb6913426626fdb4c3fd0a008 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 4 Jan 2023 15:05:36 +0100 Subject: [PATCH 187/211] OP-4490 - safer resolving if site is active --- openpype/modules/sync_server/providers/dropbox.py | 2 +- openpype/modules/sync_server/providers/gdrive.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/sync_server/providers/dropbox.py b/openpype/modules/sync_server/providers/dropbox.py index 3515aee93f..a517e7d847 100644 --- a/openpype/modules/sync_server/providers/dropbox.py +++ b/openpype/modules/sync_server/providers/dropbox.py @@ -165,7 +165,7 @@ class DropboxHandler(AbstractProvider): Returns: (boolean) """ - return self.presets["enabled"] and self.dbx is not None + return self.presets.get("enabled") and self.dbx is not None @classmethod def get_configurable_items(cls): diff --git a/openpype/modules/sync_server/providers/gdrive.py b/openpype/modules/sync_server/providers/gdrive.py index 297a5c9fec..4e24fe41d2 100644 --- a/openpype/modules/sync_server/providers/gdrive.py +++ b/openpype/modules/sync_server/providers/gdrive.py @@ -119,7 +119,7 @@ class GDriveHandler(AbstractProvider): Returns: (boolean) """ - return self.presets["enabled"] and self.service is not None + return self.presets.get("enabled") and self.service is not None @classmethod def get_system_settings_schema(cls): From 8527554c2d3bafd1a7eb796219fe7cefebcf749b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 4 Jan 2023 15:07:36 +0100 Subject: [PATCH 188/211] OP-4490 - fixed unnecessary checks Configured sites were checked all the time even if they weren't used. Now it checks only sites that are set for project. --- openpype/modules/sync_server/sync_server.py | 67 ++++++--------------- 1 file changed, 17 insertions(+), 50 deletions(-) diff --git a/openpype/modules/sync_server/sync_server.py b/openpype/modules/sync_server/sync_server.py index d0a40a60ff..d1ca69a31c 100644 --- a/openpype/modules/sync_server/sync_server.py +++ b/openpype/modules/sync_server/sync_server.py @@ -169,7 +169,7 @@ def resolve_paths(module, file_path, project_name, return local_file_path, remote_file_path -def site_is_working(module, project_name, site_name): +def _site_is_working(module, project_name, site_name, site_config): """ Confirm that 'site_name' is configured correctly for 'project_name'. @@ -179,54 +179,17 @@ def site_is_working(module, project_name, site_name): module (SyncServerModule) project_name(string): site_name(string): + site_config (dict): configuration for site from Settings Returns (bool) """ - if _get_configured_sites(module, project_name).get(site_name): - return True - return False + provider = module.get_provider_for_site(site=site_name) + handler = lib.factory.get_provider(provider, + project_name, + site_name, + presets=site_config) - -def _get_configured_sites(module, project_name): - """ - Loops through settings and looks for configured sites and checks - its handlers for particular 'project_name'. - - Args: - project_setting(dict): dictionary from Settings - only_project_name(string, optional): only interested in - particular project - Returns: - (dict of dict) - {'ProjectA': {'studio':True, 'gdrive':False}} - """ - settings = module.get_sync_project_setting(project_name) - return _get_configured_sites_from_setting(module, project_name, settings) - - -def _get_configured_sites_from_setting(module, project_name, project_setting): - if not project_setting.get("enabled"): - return {} - - initiated_handlers = {} - configured_sites = {} - all_sites = module._get_default_site_configs() - all_sites.update(project_setting.get("sites")) - for site_name, config in all_sites.items(): - provider = module.get_provider_for_site(site=site_name) - handler = initiated_handlers.get((provider, site_name)) - if not handler: - handler = lib.factory.get_provider(provider, - project_name, - site_name, - presets=config) - initiated_handlers[(provider, site_name)] = \ - handler - - if handler.is_active(): - configured_sites[site_name] = True - - return configured_sites + return handler.is_active() class SyncServerThread(threading.Thread): @@ -288,7 +251,8 @@ class SyncServerThread(threading.Thread): for project_name in enabled_projects: preset = self.module.sync_project_settings[project_name] - local_site, remote_site = self._working_sites(project_name) + local_site, remote_site = self._working_sites(project_name, + preset) if not all([local_site, remote_site]): continue @@ -464,7 +428,7 @@ class SyncServerThread(threading.Thread): self.timer.cancel() self.timer = None - def _working_sites(self, project_name): + def _working_sites(self, project_name, sync_config): if self.module.is_project_paused(project_name): self.log.debug("Both sites same, skipping") return None, None @@ -476,9 +440,12 @@ class SyncServerThread(threading.Thread): local_site, remote_site)) return None, None - configured_sites = _get_configured_sites(self.module, project_name) - if not all([local_site in configured_sites, - remote_site in configured_sites]): + local_site_config = sync_config.get('sites')[local_site] + remote_site_config = sync_config.get('sites')[remote_site] + if not all([_site_is_working(self.module, project_name, local_site, + local_site_config), + _site_is_working(self.module, project_name, remote_site, + remote_site_config)]): self.log.debug( "Some of the sites {} - {} is not working properly".format( local_site, remote_site From 307a10e123ad0c177248b144f5a2aadc2c503491 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 4 Jan 2023 15:35:43 +0100 Subject: [PATCH 189/211] Implement validate frame range repair for Render Layers - fix #3302 --- .../plugins/publish/validate_frame_range.py | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/validate_frame_range.py b/openpype/hosts/maya/plugins/publish/validate_frame_range.py index dec2f00700..d86925184e 100644 --- a/openpype/hosts/maya/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/maya/plugins/publish/validate_frame_range.py @@ -5,6 +5,11 @@ from openpype.pipeline.publish import ( RepairAction, ValidateContentsOrder, ) +from openpype.hosts.maya.api.lib_rendersetup import ( + get_attr_overrides, + get_attr_in_layer, +) +from maya.app.renderSetup.model.override import AbsOverride class ValidateFrameRange(pyblish.api.InstancePlugin): @@ -93,6 +98,11 @@ class ValidateFrameRange(pyblish.api.InstancePlugin): Repair instance container to match asset data. """ + if "renderlayer" in instance.data.get("families"): + # Special behavior for renderlayers + cls.repair_renderlayer(instance) + return + node = instance.data["name"] context = instance.context @@ -120,3 +130,53 @@ class ValidateFrameRange(pyblish.api.InstancePlugin): # Include end handle in frame end if no separate handleEnd # attribute exists on the node cmds.setAttr("{}.frameEnd".format(node), frame_end_handle) + + @classmethod + def repair_renderlayer(cls, instance): + """Apply frame range in render settings""" + + layer = instance.data["setMembers"] + context = instance.context + + start_attr = "defaultRenderGlobals.startFrame" + end_attr = "defaultRenderGlobals.endFrame" + + frame_start_handle = int(context.data.get("frameStartHandle")) + frame_end_handle = int(context.data.get("frameEndHandle")) + + cls._set_attr_in_layer(start_attr, layer, frame_start_handle) + cls._set_attr_in_layer(end_attr, layer, frame_end_handle) + + @classmethod + def _set_attr_in_layer(cls, node_attr, layer, value): + + if get_attr_in_layer(node_attr, layer=layer) == value: + # Already ok. This can happen if you have multiple renderlayers + # validated and there are no frame range overrides. The first + # layer's repair would have fixed the global value already + return + + overrides = list(get_attr_overrides(node_attr, layer=layer)) + if overrides: + # We set the last absolute override if it is an absolute override + # otherwise we'll add an Absolute override + last_override = overrides[-1][1] + if not isinstance(last_override, AbsOverride): + collection = last_override.parent() + node, attr = node_attr.split(".", 1) + last_override = collection.createAbsoluteOverride(node, attr) + + cls.log.debug("Setting {attr} absolute override in " + "layer '{layer}': {value}".format(layer=layer, + attr=node_attr, + value=value)) + cmds.setAttr(last_override.name() + ".attrValue", value) + + else: + # Set the attribute directly + # (Note that this will set the global attribute) + cls.log.debug("Setting global {attr}: {value}".format( + attr=node_attr, + value=value + )) + cmds.setAttr(node_attr, value) From e353095c24e219914f41b323feba9214f85c38fb Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 4 Jan 2023 15:36:19 +0100 Subject: [PATCH 190/211] Only apply deadline attributes when Deadline is enabled (fixes Create Render with Deadline module disabled) --- .../maya/plugins/create/create_render.py | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index a3e1272652..8375149442 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -72,15 +72,19 @@ class CreateRender(plugin.Creator): def __init__(self, *args, **kwargs): """Constructor.""" super(CreateRender, self).__init__(*args, **kwargs) - deadline_settings = get_system_settings()["modules"]["deadline"] - if not deadline_settings["enabled"]: - self.deadline_servers = {} - return + + # Defaults self._project_settings = get_project_settings( legacy_io.Session["AVALON_PROJECT"]) if self._project_settings["maya"]["RenderSettings"]["apply_render_settings"]: # noqa lib_rendersettings.RenderSettings().set_default_renderer_settings() + + # Deadline-only manager = ModulesManager() + deadline_settings = get_system_settings()["modules"]["deadline"] + if not deadline_settings["enabled"]: + self.deadline_servers = {} + return self.deadline_module = manager.modules_by_name["deadline"] try: default_servers = deadline_settings["deadline_urls"] @@ -193,8 +197,6 @@ class CreateRender(plugin.Creator): pool_names = [] default_priority = 50 - self.server_aliases = list(self.deadline_servers.keys()) - self.data["deadlineServers"] = self.server_aliases self.data["suspendPublishJob"] = False self.data["review"] = True self.data["extendFrames"] = False @@ -233,6 +235,9 @@ class CreateRender(plugin.Creator): raise RuntimeError("Both Deadline and Muster are enabled") if deadline_enabled: + self.server_aliases = list(self.deadline_servers.keys()) + self.data["deadlineServers"] = self.server_aliases + try: deadline_url = self.deadline_servers["default"] except KeyError: @@ -254,6 +259,19 @@ class CreateRender(plugin.Creator): default_priority) self.data["tile_priority"] = tile_priority + pool_setting = (self._project_settings["deadline"] + ["publish"] + ["CollectDeadlinePools"]) + primary_pool = pool_setting["primary_pool"] + self.data["primaryPool"] = self._set_default_pool(pool_names, + primary_pool) + # We add a string "-" to allow the user to not + # set any secondary pools + pool_names = ["-"] + pool_names + secondary_pool = pool_setting["secondary_pool"] + self.data["secondaryPool"] = self._set_default_pool(pool_names, + secondary_pool) + if muster_enabled: self.log.info(">>> Loading Muster credentials ...") self._load_credentials() @@ -273,18 +291,6 @@ class CreateRender(plugin.Creator): self.log.info(" - pool: {}".format(pool["name"])) pool_names.append(pool["name"]) - pool_setting = (self._project_settings["deadline"] - ["publish"] - ["CollectDeadlinePools"]) - primary_pool = pool_setting["primary_pool"] - self.data["primaryPool"] = self._set_default_pool(pool_names, - primary_pool) - # We add a string "-" to allow the user to not - # set any secondary pools - pool_names = ["-"] + pool_names - secondary_pool = pool_setting["secondary_pool"] - self.data["secondaryPool"] = self._set_default_pool(pool_names, - secondary_pool) self.options = {"useSelection": False} # Force no content def _set_default_pool(self, pool_names, pool_value): From d3f09c075badd52f3faa9d4fe41678dd1abf1d9b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 4 Jan 2023 15:39:13 +0100 Subject: [PATCH 191/211] OP-4490 - Hound --- openpype/modules/sync_server/sync_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/sync_server/sync_server.py b/openpype/modules/sync_server/sync_server.py index d1ca69a31c..85b0774e90 100644 --- a/openpype/modules/sync_server/sync_server.py +++ b/openpype/modules/sync_server/sync_server.py @@ -443,9 +443,9 @@ class SyncServerThread(threading.Thread): local_site_config = sync_config.get('sites')[local_site] remote_site_config = sync_config.get('sites')[remote_site] if not all([_site_is_working(self.module, project_name, local_site, - local_site_config), + local_site_config), _site_is_working(self.module, project_name, remote_site, - remote_site_config)]): + remote_site_config)]): self.log.debug( "Some of the sites {} - {} is not working properly".format( local_site, remote_site From 30bd8d806e1e48a1b2ad699daf7ffe278e9670dc Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 5 Jan 2023 16:06:13 +0100 Subject: [PATCH 192/211] :bug: fix cosmetic issues --- tools/create_env.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/create_env.ps1 b/tools/create_env.ps1 index cdb97d4942..75cba3f65e 100644 --- a/tools/create_env.ps1 +++ b/tools/create_env.ps1 @@ -19,7 +19,7 @@ PS> .\create_env.ps1 --verbose #> $arguments=$ARGS -$poetry_verbosity="" +$poetry_verbosity=$null if($arguments -eq "--verbose") { $poetry_verbosity="-vvv" } @@ -101,11 +101,11 @@ print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1])) Exit-WithCode 1 } # We are supporting python 3.7 only - if (($matches[1] -lt 3) -or ($matches[2] -lt 7)) { + if (([int]$matches[1] -lt 3) -or ([int]$matches[2] -lt 7)) { Write-Color -Text "FAILED ", "Version ", "[", $p ,"]", "is old and unsupported" -Color Red, Yellow, Cyan, White, Cyan, Yellow Set-Location -Path $current_dir Exit-WithCode 1 - } elseif (($matches[1] -eq 3) -and ($matches[2] -gt 7)) { + } elseif (([int]$matches[1] -eq 3) -and ([int]$matches[2] -gt 7)) { Write-Color -Text "WARNING Version ", "[", $p, "]", " is unsupported, use at your own risk." -Color Yellow, Cyan, White, Cyan, Yellow Write-Color -Text "*** ", "OpenPype supports only Python 3.7" -Color Yellow, White } else { From 9399314761068e98a2036bfe552bdb2bbdaf0aa1 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 5 Jan 2023 16:07:54 +0100 Subject: [PATCH 193/211] :arrow_up: update dependencies and add pre-commit --- poetry.lock | 1626 +++++++++++++++++++++++++++++++++--------------- pyproject.toml | 1 + 2 files changed, 1126 insertions(+), 501 deletions(-) diff --git a/poetry.lock b/poetry.lock index 21b6bda880..c5aab5c3b3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -15,7 +15,7 @@ resolved_reference = "126f7a188cfe36718f707f42ebbc597e86aa86c3" [[package]] name = "aiohttp" -version = "3.8.1" +version = "3.8.3" description = "Async http client/server framework (asyncio)" category = "main" optional = false @@ -48,7 +48,7 @@ aiohttp = ">=3,<4" [[package]] name = "aiohttp-middlewares" -version = "2.1.0" +version = "2.2.0" description = "Collection of useful middlewares for aiohttp applications." category = "main" optional = false @@ -61,11 +61,11 @@ yarl = ">=1.5.1,<2.0.0" [[package]] name = "aiosignal" -version = "1.2.0" +version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] frozenlist = ">=1.1.0" @@ -99,7 +99,7 @@ develop = false type = "git" url = "https://github.com/ActiveState/appdirs.git" reference = "master" -resolved_reference = "193a2cbba58cce2542882fcedd0e49f6763672ed" +resolved_reference = "211708144ddcbba1f02e26a43efec9aef57bc9fc" [[package]] name = "arrow" @@ -155,17 +155,19 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "22.1.0" +version = "22.2.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] -docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"] +cov = ["attrs", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] +dev = ["attrs"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] +tests = ["attrs", "zope.interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=0.971,<0.990)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist"] +tests_no_zope = ["cloudpickle", "hypothesis", "mypy (>=0.971,<0.990)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist"] [[package]] name = "autopep8" @@ -181,7 +183,7 @@ toml = "*" [[package]] name = "babel" -version = "2.10.3" +version = "2.11.0" description = "Internationalization utilities" category = "dev" optional = false @@ -192,15 +194,12 @@ pytz = ">=2015.7" [[package]] name = "bcrypt" -version = "3.2.2" +version = "4.0.1" description = "Modern password hashing for your software and your servers" category = "main" optional = false python-versions = ">=3.6" -[package.dependencies] -cffi = ">=1.1" - [package.extras] tests = ["pytest (>=3.2.1,!=3.3.0)"] typecheck = ["mypy"] @@ -228,7 +227,7 @@ python-versions = "~=3.7" [[package]] name = "certifi" -version = "2022.6.15" +version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false @@ -245,13 +244,21 @@ python-versions = "*" [package.dependencies] pycparser = "*" +[[package]] +name = "cfgv" +version = "3.3.1" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6.1" + [[package]] name = "charset-normalizer" -version = "2.0.12" +version = "2.1.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false -python-versions = ">=3.5.0" +python-versions = ">=3.6.0" [package.extras] unicode_backport = ["unicodedata2"] @@ -273,17 +280,17 @@ optional = false python-versions = ">=2.7, <4.0" [package.extras] -dev = ["sphinx (>=2,<4)", "sphinx-rtd-theme (>=0.1.6,<1)", "lowdown (>=0.2.0,<1)", "pytest-runner (>=2.7,<3)", "pytest (>=2.3.5,<5)", "pytest-cov (>=2,<3)"] -doc = ["sphinx (>=2,<4)", "sphinx-rtd-theme (>=0.1.6,<1)", "lowdown (>=0.2.0,<1)"] -test = ["pytest-runner (>=2.7,<3)", "pytest (>=2.3.5,<5)", "pytest-cov (>=2,<3)"] +dev = ["lowdown (>=0.2.0,<1)", "pytest (>=2.3.5,<5)", "pytest-cov (>=2,<3)", "pytest-runner (>=2.7,<3)", "sphinx (>=2,<4)", "sphinx-rtd-theme (>=0.1.6,<1)"] +doc = ["lowdown (>=0.2.0,<1)", "sphinx (>=2,<4)", "sphinx-rtd-theme (>=0.1.6,<1)"] +test = ["pytest (>=2.3.5,<5)", "pytest-cov (>=2,<3)", "pytest-runner (>=2.7,<3)"] [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" [[package]] name = "commonmark" @@ -298,7 +305,7 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] name = "coolname" -version = "1.1.0" +version = "2.1.0" description = "Random name and slug generator" category = "main" optional = false @@ -306,7 +313,7 @@ python-versions = "*" [[package]] name = "coverage" -version = "6.4.3" +version = "7.0.3" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -320,7 +327,7 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "37.0.4" +version = "39.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -330,12 +337,12 @@ python-versions = ">=3.6" cffi = ">=1.12" [package.extras] -docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] -docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] -pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] -sdist = ["setuptools_rust (>=0.11.4)"] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1,!=5.2.0,!=5.2.0.post0)", "sphinx-rtd-theme"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +pep8test = ["black", "ruff"] +sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] [[package]] name = "cx-freeze" @@ -351,11 +358,11 @@ importlib-metadata = ">=4.3.1" [[package]] name = "cx-logging" -version = "3.0" +version = "3.1.0" description = "Python and C interfaces for logging" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" [[package]] name = "deprecated" @@ -369,19 +376,27 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" wrapt = ">=1.10,<2" [package.extras] -dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] +dev = ["PyTest (<5)", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "pytest", "pytest-cov", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] [[package]] name = "dill" -version = "0.3.5.1" +version = "0.3.6" description = "serialize all of python" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +python-versions = ">=3.7" [package.extras] graph = ["objgraph (>=1.7.2)"] +[[package]] +name = "distlib" +version = "0.3.6" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "dnspython" version = "2.2.1" @@ -391,8 +406,8 @@ optional = false python-versions = ">=3.6,<4.0" [package.extras] -dnssec = ["cryptography (>=2.6,<37.0)"] curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] +dnssec = ["cryptography (>=2.6,<37.0)"] doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"] idna = ["idna (>=2.1,<4.0)"] trio = ["trio (>=0.14,<0.20)"] @@ -408,7 +423,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "dropbox" -version = "11.33.0" +version = "11.36.0" description = "Official Dropbox API Client" category = "main" optional = false @@ -421,7 +436,7 @@ stone = ">=2" [[package]] name = "enlighten" -version = "1.10.2" +version = "1.11.1" description = "Enlighten Progress Bar" category = "main" optional = false @@ -439,6 +454,18 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "filelock" +version = "3.9.0" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] + [[package]] name = "flake8" version = "3.9.2" @@ -455,7 +482,7 @@ pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "frozenlist" -version = "1.3.1" +version = "1.3.3" description = "A list-like structure which implements collections.abc.MutableSequence" category = "main" optional = false @@ -490,7 +517,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "gazu" -version = "0.8.30" +version = "0.8.34" description = "Gazu is a client for Zou, the API to store the data of your CG production." category = "main" optional = false @@ -499,26 +526,26 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] deprecated = "1.2.13" python-socketio = {version = "4.6.1", extras = ["client"], markers = "python_version >= \"3.5\""} -requests = ">=2.25.1,<=2.27.1" +requests = ">=2.25.1,<=2.28.1" [package.extras] dev = ["wheel"] -test = ["pytest-cov (==2.12.1)", "requests-mock (==1.9.3)", "pytest (==4.6.11)", "pytest (==6.1.2)", "pytest (==6.2.5)", "black (==21.12b0)", "pre-commit (==2.17.0)"] +test = ["black (<=22.8.0)", "pre-commit (<=2.20.0)", "pytest (<=7.1.3)", "pytest-cov (<=3.0.0)", "requests-mock (==1.10.0)"] [[package]] name = "gitdb" -version = "4.0.9" +version = "4.0.10" description = "Git Object Database" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.27" +version = "3.1.30" description = "GitPython is a python library used to interact with Git repositories" category = "dev" optional = false @@ -530,20 +557,22 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\"" [[package]] name = "google-api-core" -version = "2.8.2" +version = "2.11.0" description = "Google API client core library" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -google-auth = ">=1.25.0,<3.0dev" +google-auth = ">=2.14.1,<3.0dev" googleapis-common-protos = ">=1.56.2,<2.0dev" -protobuf = ">=3.15.0,<5.0.0dev" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" requests = ">=2.18.0,<3.0.0dev" [package.extras] -grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio-status (>=1.33.2,<2.0dev)"] +grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0dev)", "grpcio-status (>=1.49.1,<2.0dev)"] +grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0dev)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0dev)"] [[package]] name = "google-api-python-client" @@ -563,7 +592,7 @@ uritemplate = ">=3.0.0,<4dev" [[package]] name = "google-auth" -version = "2.10.0" +version = "2.15.0" description = "Google Authentication Library" category = "main" optional = false @@ -576,9 +605,9 @@ rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""} six = ">=1.9.0" [package.extras] -aiohttp = ["requests (>=2.20.0,<3.0.0dev)", "aiohttp (>=3.6.2,<4.0.0dev)"] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "requests (>=2.20.0,<3.0.0dev)"] enterprise_cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] -pyopenssl = ["pyopenssl (>=20.0.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] [[package]] @@ -596,21 +625,21 @@ six = "*" [[package]] name = "googleapis-common-protos" -version = "1.56.4" +version = "1.57.1" description = "Common protobufs used in Google APIs" category = "main" optional = false python-versions = ">=3.7" [package.dependencies] -protobuf = ">=3.15.0,<5.0.0dev" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" [package.extras] -grpc = ["grpcio (>=1.0.0,<2.0.0dev)"] +grpc = ["grpcio (>=1.44.0,<2.0.0dev)"] [[package]] name = "httplib2" -version = "0.20.4" +version = "0.21.0" description = "A comprehensive HTTP client library." category = "main" optional = false @@ -619,9 +648,20 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pyparsing = {version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0.2,<3.0.3 || >3.0.3,<4", markers = "python_version > \"3.0\""} +[[package]] +name = "identify" +version = "2.5.12" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +license = ["ukkonen"] + [[package]] name = "idna" -version = "3.3" +version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -637,7 +677,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.12.0" +version = "6.0.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -648,9 +688,9 @@ typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "iniconfig" @@ -662,17 +702,17 @@ python-versions = "*" [[package]] name = "isort" -version = "5.10.1" +version = "5.11.4" description = "A Python utility / library to sort Python imports." category = "dev" optional = false -python-versions = ">=3.6.1,<4.0" +python-versions = ">=3.7.0" [package.extras] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile-deprecated-finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "jedi" @@ -697,8 +737,8 @@ optional = false python-versions = ">=3.7" [package.extras] +test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] trio = ["async-generator", "trio"] -test = ["async-timeout", "trio", "testpath", "pytest-asyncio (>=0.17)", "pytest-trio", "pytest"] [[package]] name = "jinja2" @@ -751,16 +791,16 @@ pywin32-ctypes = {version = "<0.1.0 || >0.1.0,<0.1.1 || >0.1.1", markers = "sys_ SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] +testing = ["pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-enabler", "pytest-flake8", "pytest-mypy"] [[package]] name = "lazy-object-proxy" -version = "1.7.1" +version = "1.9.0" description = "A fast and thorough lazy object proxy." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "log4mongo" @@ -791,12 +831,20 @@ python-versions = "*" [[package]] name = "multidict" -version = "6.0.2" +version = "6.0.4" description = "multidict implementation" category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "nodeenv" +version = "1.7.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" + [[package]] name = "opentimelineio" version = "0.14.0.dev1" @@ -809,7 +857,7 @@ python-versions = "*" pyaaf2 = "1.4.0" [package.extras] -dev = ["check-manifest", "flake8 (>=3.5)", "coverage (>=4.5)", "urllib3 (>=1.24.3)"] +dev = ["check-manifest", "coverage (>=4.5)", "flake8 (>=3.5)", "urllib3 (>=1.24.3)"] view = ["PySide2 (>=5.11,<6.0)"] [package.source] @@ -819,18 +867,15 @@ reference = "openpype" [[package]] name = "packaging" -version = "21.3" +version = "22.0" description = "Core utilities for Python packages" category = "dev" optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +python-versions = ">=3.7" [[package]] name = "paramiko" -version = "2.11.0" +version = "2.12.0" description = "SSH2 protocol library" category = "main" optional = false @@ -843,9 +888,9 @@ pynacl = ">=1.0.1" six = "*" [package.extras] -all = ["pyasn1 (>=0.1.7)", "pynacl (>=1.0.1)", "bcrypt (>=3.1.3)", "invoke (>=1.3)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] -ed25519 = ["pynacl (>=1.0.1)", "bcrypt (>=3.1.3)"] -gssapi = ["pyasn1 (>=0.1.7)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] +all = ["bcrypt (>=3.1.3)", "gssapi (>=1.4.1)", "invoke (>=1.3)", "pyasn1 (>=0.1.7)", "pynacl (>=1.0.1)", "pywin32 (>=2.1.8)"] +ed25519 = ["bcrypt (>=3.1.3)", "pynacl (>=1.0.1)"] +gssapi = ["gssapi (>=1.4.1)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8)"] invoke = ["invoke (>=1.3)"] [[package]] @@ -873,27 +918,30 @@ six = "*" [[package]] name = "pillow" -version = "9.2.0" +version = "9.4.0" description = "Python Imaging Library (Fork)" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] [[package]] name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "2.6.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" +[package.dependencies] +typing-extensions = {version = ">=4.4", markers = "python_version < \"3.8\""} + [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] -test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" @@ -918,9 +966,25 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "pre-commit" +version = "2.21.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + [[package]] name = "prefixed" -version = "0.3.2" +version = "0.5.0" description = "Prefixed alternative numeric library" category = "main" optional = false @@ -928,7 +992,7 @@ python-versions = "*" [[package]] name = "protobuf" -version = "4.21.5" +version = "4.21.12" description = "" category = "main" optional = false @@ -1015,12 +1079,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.12.0" +version = "2.14.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false python-versions = ">=3.6" +[package.extras] +plugins = ["importlib-metadata"] + [[package]] name = "pylint" version = "2.13.9" @@ -1044,7 +1111,7 @@ testutil = ["gitpython (>3)"] [[package]] name = "pymongo" -version = "3.12.3" +version = "3.13.0" description = "Python driver for MongoDB " category = "main" optional = false @@ -1054,7 +1121,7 @@ python-versions = "*" aws = ["pymongo-auth-aws (<2.0.0)"] encryption = ["pymongocrypt (>=1.1.0,<2.0.0)"] gssapi = ["pykerberos"] -ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)", "certifi"] +ocsp = ["certifi", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] srv = ["dnspython (>=1.16.0,<1.17.0)"] tls = ["ipaddress"] @@ -1073,7 +1140,7 @@ cffi = ">=1.4.1" [package.extras] docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] -tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] [[package]] name = "pynput" @@ -1092,47 +1159,47 @@ six = "*" [[package]] name = "pyobjc-core" -version = "8.5" +version = "9.0.1" description = "Python<->ObjC Interoperability Module" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "pyobjc-framework-applicationservices" -version = "8.5" +version = "9.0.1" description = "Wrappers for the framework ApplicationServices on macOS" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -pyobjc-core = ">=8.5" -pyobjc-framework-Cocoa = ">=8.5" -pyobjc-framework-Quartz = ">=8.5" +pyobjc-core = ">=9.0.1" +pyobjc-framework-Cocoa = ">=9.0.1" +pyobjc-framework-Quartz = ">=9.0.1" [[package]] name = "pyobjc-framework-cocoa" -version = "8.5" +version = "9.0.1" description = "Wrappers for the Cocoa frameworks on macOS" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -pyobjc-core = ">=8.5" +pyobjc-core = ">=9.0.1" [[package]] name = "pyobjc-framework-quartz" -version = "8.5" +version = "9.0.1" description = "Wrappers for the Quartz frameworks on macOS" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -pyobjc-core = ">=8.5" -pyobjc-framework-Cocoa = ">=8.5" +pyobjc-core = ">=9.0.1" +pyobjc-framework-Cocoa = ">=9.0.1" [[package]] name = "pyparsing" @@ -1177,7 +1244,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "pytest-cov" -version = "3.0.0" +version = "4.0.0" description = "Pytest plugin for measuring coverage." category = "dev" optional = false @@ -1188,7 +1255,7 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "pytest-print" @@ -1250,7 +1317,7 @@ client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] name = "python-xlib" -version = "0.31" +version = "0.33" description = "Python X Library" category = "main" optional = false @@ -1269,7 +1336,7 @@ python-versions = "*" [[package]] name = "pytz" -version = "2022.2" +version = "2022.7" description = "World timezone definitions, modern and historical" category = "dev" optional = false @@ -1291,6 +1358,14 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + [[package]] name = "qt.py" version = "1.3.7" @@ -1334,21 +1409,21 @@ sphinx = ">=1.3.1" [[package]] name = "requests" -version = "2.27.1" +version = "2.28.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7, <4" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" [package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rsa" @@ -1363,7 +1438,7 @@ pyasn1 = ">=0.1.3" [[package]] name = "secretstorage" -version = "3.3.2" +version = "3.3.3" description = "Python bindings to FreeDesktop.org Secret Service API" category = "main" optional = false @@ -1406,15 +1481,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "slack-sdk" -version = "3.18.1" +version = "3.19.5" description = "The Slack API Platform SDK for Python" category = "main" optional = false python-versions = ">=3.6.0" [package.extras] -optional = ["aiodns (>1.0)", "aiohttp (>=3.7.3,<4)", "boto3 (<=2)", "SQLAlchemy (>=1,<2)", "websockets (>=10,<11)", "websocket-client (>=1,<2)"] -testing = ["pytest (>=6.2.5,<7)", "pytest-asyncio (<1)", "Flask-Sockets (>=0.2,<1)", "Flask (>=1,<2)", "Werkzeug (<2)", "itsdangerous (==1.1.0)", "Jinja2 (==3.0.3)", "pytest-cov (>=2,<3)", "codecov (>=2,<3)", "flake8 (>=4,<5)", "black (==22.3.0)", "click (==8.0.4)", "psutil (>=5,<6)", "databases (>=0.5)", "boto3 (<=2)", "moto (>=3,<4)"] +optional = ["SQLAlchemy (>=1,<2)", "aiodns (>1.0)", "aiohttp (>=3.7.3,<4)", "boto3 (<=2)", "websocket-client (>=1,<2)", "websockets (>=10,<11)"] +testing = ["Flask (>=1,<2)", "Flask-Sockets (>=0.2,<1)", "Jinja2 (==3.0.3)", "Werkzeug (<2)", "black (==22.8.0)", "boto3 (<=2)", "click (==8.0.4)", "codecov (>=2,<3)", "databases (>=0.5)", "flake8 (>=5,<6)", "itsdangerous (==1.1.0)", "moto (>=3,<4)", "psutil (>=5,<6)", "pytest (>=6.2.5,<7)", "pytest-asyncio (<1)", "pytest-cov (>=2,<3)"] [[package]] name = "smmap" @@ -1469,12 +1544,12 @@ sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.950)", "docutils-stubs", "types-typed-ast", "types-requests"] -test = ["pytest (>=4.6)", "html5lib", "cython", "typed-ast"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "isort", "mypy (>=0.950)", "types-requests", "types-typed-ast"] +test = ["cython", "html5lib", "pytest (>=4.6)", "typed-ast"] [[package]] name = "sphinx-qt-documentation" -version = "0.4" +version = "0.4.1" description = "Plugin for proper resolve intersphinx references for Qt elements" category = "dev" optional = false @@ -1485,24 +1560,24 @@ docutils = "*" sphinx = "*" [package.extras] -test = ["pytest-cov", "pytest (>=3.0.0)"] -lint = ["pylint", "flake8", "black"] dev = ["pre-commit"] +lint = ["black", "flake8", "pylint"] +test = ["pytest (>=3.0.0)", "pytest-cov"] [[package]] name = "sphinx-rtd-theme" -version = "1.0.0" +version = "1.1.1" description = "Read the Docs theme for Sphinx" category = "dev" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" [package.dependencies] docutils = "<0.18" -sphinx = ">=1.6" +sphinx = ">=1.6,<6" [package.extras] -dev = ["transifex-client", "sphinxcontrib-httpdomain", "bump2version"] +dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] [[package]] name = "sphinxcontrib-applehelp" @@ -1513,7 +1588,7 @@ optional = false python-versions = ">=3.5" [package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] +lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] [[package]] @@ -1525,7 +1600,7 @@ optional = false python-versions = ">=3.5" [package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] +lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] [[package]] @@ -1537,8 +1612,8 @@ optional = false python-versions = ">=3.6" [package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] -test = ["pytest", "html5lib"] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["html5lib", "pytest"] [[package]] name = "sphinxcontrib-jsmath" @@ -1549,7 +1624,7 @@ optional = false python-versions = ">=3.5" [package.extras] -test = ["pytest", "flake8", "mypy"] +test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" @@ -1560,7 +1635,7 @@ optional = false python-versions = ">=3.5" [package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] +lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] [[package]] @@ -1572,7 +1647,7 @@ optional = false python-versions = ">=3.5" [package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] +lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] [[package]] @@ -1588,7 +1663,7 @@ sphinxcontrib-serializinghtml = "*" [package.extras] lint = ["flake8"] -test = ["pytest", "sqlalchemy", "whoosh", "sphinx"] +test = ["pytest", "sphinx", "sqlalchemy", "whoosh"] [[package]] name = "stone" @@ -1636,7 +1711,7 @@ python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "4.3.0" +version = "4.4.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false @@ -1652,17 +1727,35 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "urllib3" -version = "1.26.11" +version = "1.26.13" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.extras] -brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +[[package]] +name = "virtualenv" +version = "20.17.1" +description = "Virtual Python Environment builder" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +distlib = ">=0.3.6,<1" +filelock = ">=3.4.1,<4" +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""} +platformdirs = ">=2.4,<3" + +[package.extras] +docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"] +testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] + [[package]] name = "wcwidth" version = "0.2.5" @@ -1704,12 +1797,12 @@ yarl = "*" [package.extras] develop = ["async-timeout", "coverage (!=4.3)", "coveralls", "pytest", "pytest-aiohttp", "pytest-cov", "sphinx", "sphinxcontrib-plantuml", "tox (>=2.4)"] -testing = ["async-timeout", "pytest", "pytest-aiohttp", "pytest-cov", "coverage (!=4.3)", "coveralls"] +testing = ["async-timeout", "coverage (!=4.3)", "coveralls", "pytest", "pytest-aiohttp", "pytest-cov"] ujson = ["ujson"] [[package]] name = "yarl" -version = "1.8.1" +version = "1.8.2" description = "Yet another URL library" category = "main" optional = false @@ -1722,105 +1815,123 @@ typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [[package]] name = "zipp" -version = "3.8.1" +version = "3.11.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "de7422afb6aed02f75e1696afdda9ad6c7bf32da76b5022ee3e8f71a1ac4bae2" +content-hash = "3221793aa16f563b026610bb5cccf8ae7faff72fd29b3c84d24cf7955e9d67c1" [metadata.files] acre = [] aiohttp = [ - {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"}, - {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8"}, - {file = "aiohttp-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1"}, - {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3"}, - {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2"}, - {file = "aiohttp-3.8.1-cp310-cp310-win32.whl", hash = "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa"}, - {file = "aiohttp-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32"}, - {file = "aiohttp-3.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091"}, - {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782"}, - {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4"}, - {file = "aiohttp-3.8.1-cp36-cp36m-win32.whl", hash = "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602"}, - {file = "aiohttp-3.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96"}, - {file = "aiohttp-3.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2"}, - {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7"}, - {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c"}, - {file = "aiohttp-3.8.1-cp37-cp37m-win32.whl", hash = "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9"}, - {file = "aiohttp-3.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17"}, - {file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785"}, - {file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b"}, - {file = "aiohttp-3.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675"}, - {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155"}, - {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33"}, - {file = "aiohttp-3.8.1-cp38-cp38-win32.whl", hash = "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a"}, - {file = "aiohttp-3.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75"}, - {file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237"}, - {file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74"}, - {file = "aiohttp-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf"}, - {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866"}, - {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2"}, - {file = "aiohttp-3.8.1-cp39-cp39-win32.whl", hash = "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1"}, - {file = "aiohttp-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac"}, - {file = "aiohttp-3.8.1.tar.gz", hash = "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578"}, + {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ba71c9b4dcbb16212f334126cc3d8beb6af377f6703d9dc2d9fb3874fd667ee9"}, + {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d24b8bb40d5c61ef2d9b6a8f4528c2f17f1c5d2d31fed62ec860f6006142e83e"}, + {file = "aiohttp-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f88df3a83cf9df566f171adba39d5bd52814ac0b94778d2448652fc77f9eb491"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97decbb3372d4b69e4d4c8117f44632551c692bb1361b356a02b97b69e18a62"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309aa21c1d54b8ef0723181d430347d7452daaff93e8e2363db8e75c72c2fb2d"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad5383a67514e8e76906a06741febd9126fc7c7ff0f599d6fcce3e82b80d026f"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20acae4f268317bb975671e375493dbdbc67cddb5f6c71eebdb85b34444ac46b"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05a3c31c6d7cd08c149e50dc7aa2568317f5844acd745621983380597f027a18"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6f76310355e9fae637c3162936e9504b4767d5c52ca268331e2756e54fd4ca5"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:256deb4b29fe5e47893fa32e1de2d73c3afe7407738bd3c63829874661d4822d"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:5c59fcd80b9049b49acd29bd3598cada4afc8d8d69bd4160cd613246912535d7"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:059a91e88f2c00fe40aed9031b3606c3f311414f86a90d696dd982e7aec48142"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2feebbb6074cdbd1ac276dbd737b40e890a1361b3cc30b74ac2f5e24aab41f7b"}, + {file = "aiohttp-3.8.3-cp310-cp310-win32.whl", hash = "sha256:5bf651afd22d5f0c4be16cf39d0482ea494f5c88f03e75e5fef3a85177fecdeb"}, + {file = "aiohttp-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:653acc3880459f82a65e27bd6526e47ddf19e643457d36a2250b85b41a564715"}, + {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:86fc24e58ecb32aee09f864cb11bb91bc4c1086615001647dbfc4dc8c32f4008"}, + {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75e14eac916f024305db517e00a9252714fce0abcb10ad327fb6dcdc0d060f1d"}, + {file = "aiohttp-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d1fde0f44029e02d02d3993ad55ce93ead9bb9b15c6b7ccd580f90bd7e3de476"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ab94426ddb1ecc6a0b601d832d5d9d421820989b8caa929114811369673235c"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89d2e02167fa95172c017732ed7725bc8523c598757f08d13c5acca308e1a061"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02f9a2c72fc95d59b881cf38a4b2be9381b9527f9d328771e90f72ac76f31ad8"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7149272fb5834fc186328e2c1fa01dda3e1fa940ce18fded6d412e8f2cf76d"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:512bd5ab136b8dc0ffe3fdf2dfb0c4b4f49c8577f6cae55dca862cd37a4564e2"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7018ecc5fe97027214556afbc7c502fbd718d0740e87eb1217b17efd05b3d276"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88c70ed9da9963d5496d38320160e8eb7e5f1886f9290475a881db12f351ab5d"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:da22885266bbfb3f78218dc40205fed2671909fbd0720aedba39b4515c038091"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:e65bc19919c910127c06759a63747ebe14f386cda573d95bcc62b427ca1afc73"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:08c78317e950e0762c2983f4dd58dc5e6c9ff75c8a0efeae299d363d439c8e34"}, + {file = "aiohttp-3.8.3-cp311-cp311-win32.whl", hash = "sha256:45d88b016c849d74ebc6f2b6e8bc17cabf26e7e40c0661ddd8fae4c00f015697"}, + {file = "aiohttp-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:96372fc29471646b9b106ee918c8eeb4cca423fcbf9a34daa1b93767a88a2290"}, + {file = "aiohttp-3.8.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c971bf3786b5fad82ce5ad570dc6ee420f5b12527157929e830f51c55dc8af77"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff25f48fc8e623d95eca0670b8cc1469a83783c924a602e0fbd47363bb54aaca"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e381581b37db1db7597b62a2e6b8b57c3deec95d93b6d6407c5b61ddc98aca6d"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db19d60d846283ee275d0416e2a23493f4e6b6028825b51290ac05afc87a6f97"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25892c92bee6d9449ffac82c2fe257f3a6f297792cdb18ad784737d61e7a9a85"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:398701865e7a9565d49189f6c90868efaca21be65c725fc87fc305906be915da"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4a4fbc769ea9b6bd97f4ad0b430a6807f92f0e5eb020f1e42ece59f3ecfc4585"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:b29bfd650ed8e148f9c515474a6ef0ba1090b7a8faeee26b74a8ff3b33617502"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:1e56b9cafcd6531bab5d9b2e890bb4937f4165109fe98e2b98ef0dcfcb06ee9d"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ec40170327d4a404b0d91855d41bfe1fe4b699222b2b93e3d833a27330a87a6d"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2df5f139233060578d8c2c975128fb231a89ca0a462b35d4b5fcf7c501ebdbe1"}, + {file = "aiohttp-3.8.3-cp36-cp36m-win32.whl", hash = "sha256:f973157ffeab5459eefe7b97a804987876dd0a55570b8fa56b4e1954bf11329b"}, + {file = "aiohttp-3.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:437399385f2abcd634865705bdc180c8314124b98299d54fe1d4c8990f2f9494"}, + {file = "aiohttp-3.8.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:09e28f572b21642128ef31f4e8372adb6888846f32fecb288c8b0457597ba61a"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f3553510abdbec67c043ca85727396ceed1272eef029b050677046d3387be8d"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e168a7560b7c61342ae0412997b069753f27ac4862ec7867eff74f0fe4ea2ad9"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db4c979b0b3e0fa7e9e69ecd11b2b3174c6963cebadeecfb7ad24532ffcdd11a"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e164e0a98e92d06da343d17d4e9c4da4654f4a4588a20d6c73548a29f176abe2"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8a78079d9a39ca9ca99a8b0ac2fdc0c4d25fc80c8a8a82e5c8211509c523363"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:21b30885a63c3f4ff5b77a5d6caf008b037cb521a5f33eab445dc566f6d092cc"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4b0f30372cef3fdc262f33d06e7b411cd59058ce9174ef159ad938c4a34a89da"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:8135fa153a20d82ffb64f70a1b5c2738684afa197839b34cc3e3c72fa88d302c"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ad61a9639792fd790523ba072c0555cd6be5a0baf03a49a5dd8cfcf20d56df48"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978b046ca728073070e9abc074b6299ebf3501e8dee5e26efacb13cec2b2dea0"}, + {file = "aiohttp-3.8.3-cp37-cp37m-win32.whl", hash = "sha256:0d2c6d8c6872df4a6ec37d2ede71eff62395b9e337b4e18efd2177de883a5033"}, + {file = "aiohttp-3.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:21d69797eb951f155026651f7e9362877334508d39c2fc37bd04ff55b2007091"}, + {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ca9af5f8f5812d475c5259393f52d712f6d5f0d7fdad9acdb1107dd9e3cb7eb"}, + {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d90043c1882067f1bd26196d5d2db9aa6d268def3293ed5fb317e13c9413ea4"}, + {file = "aiohttp-3.8.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d737fc67b9a970f3234754974531dc9afeea11c70791dcb7db53b0cf81b79784"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebf909ea0a3fc9596e40d55d8000702a85e27fd578ff41a5500f68f20fd32e6c"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5835f258ca9f7c455493a57ee707b76d2d9634d84d5d7f62e77be984ea80b849"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da37dcfbf4b7f45d80ee386a5f81122501ec75672f475da34784196690762f4b"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87f44875f2804bc0511a69ce44a9595d5944837a62caecc8490bbdb0e18b1342"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:527b3b87b24844ea7865284aabfab08eb0faf599b385b03c2aa91fc6edd6e4b6"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5ba88df9aa5e2f806650fcbeedbe4f6e8736e92fc0e73b0400538fd25a4dd96"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e7b8813be97cab8cb52b1375f41f8e6804f6507fe4660152e8ca5c48f0436017"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:2dea10edfa1a54098703cb7acaa665c07b4e7568472a47f4e64e6319d3821ccf"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:713d22cd9643ba9025d33c4af43943c7a1eb8547729228de18d3e02e278472b6"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2d252771fc85e0cf8da0b823157962d70639e63cb9b578b1dec9868dd1f4f937"}, + {file = "aiohttp-3.8.3-cp38-cp38-win32.whl", hash = "sha256:66bd5f950344fb2b3dbdd421aaa4e84f4411a1a13fca3aeb2bcbe667f80c9f76"}, + {file = "aiohttp-3.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:84b14f36e85295fe69c6b9789b51a0903b774046d5f7df538176516c3e422446"}, + {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16c121ba0b1ec2b44b73e3a8a171c4f999b33929cd2397124a8c7fcfc8cd9e06"}, + {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d6aaa4e7155afaf994d7924eb290abbe81a6905b303d8cb61310a2aba1c68ba"}, + {file = "aiohttp-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43046a319664a04b146f81b40e1545d4c8ac7b7dd04c47e40bf09f65f2437346"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599418aaaf88a6d02a8c515e656f6faf3d10618d3dd95866eb4436520096c84b"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a2964319d359f494f16011e23434f6f8ef0434acd3cf154a6b7bec511e2fb7"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73a4131962e6d91109bca6536416aa067cf6c4efb871975df734f8d2fd821b37"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598adde339d2cf7d67beaccda3f2ce7c57b3b412702f29c946708f69cf8222aa"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75880ed07be39beff1881d81e4a907cafb802f306efd6d2d15f2b3c69935f6fb"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0239da9fbafd9ff82fd67c16704a7d1bccf0d107a300e790587ad05547681c8"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4e3a23ec214e95c9fe85a58470b660efe6534b83e6cbe38b3ed52b053d7cb6ad"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:47841407cc89a4b80b0c52276f3cc8138bbbfba4b179ee3acbd7d77ae33f7ac4"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:54d107c89a3ebcd13228278d68f1436d3f33f2dd2af5415e3feaeb1156e1a62c"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c37c5cce780349d4d51739ae682dec63573847a2a8dcb44381b174c3d9c8d403"}, + {file = "aiohttp-3.8.3-cp39-cp39-win32.whl", hash = "sha256:f178d2aadf0166be4df834c4953da2d7eef24719e8aec9a65289483eeea9d618"}, + {file = "aiohttp-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:88e5be56c231981428f4f506c68b6a46fa25c4123a2e86d156c58a8369d31ab7"}, + {file = "aiohttp-3.8.3.tar.gz", hash = "sha256:3828fb41b7203176b82fe5d699e0d845435f2374750a44b480ea6b930f6be269"}, ] aiohttp-json-rpc = [ {file = "aiohttp-json-rpc-0.13.3.tar.gz", hash = "sha256:6237a104478c22c6ef96c7227a01d6832597b414e4b79a52d85593356a169e99"}, {file = "aiohttp_json_rpc-0.13.3-py3-none-any.whl", hash = "sha256:4fbd197aced61bd2df7ae3237ead7d3e08833c2ccf48b8581e1828c95ebee680"}, ] -aiohttp-middlewares = [] +aiohttp-middlewares = [ + {file = "aiohttp_middlewares-2.2.0-py3-none-any.whl", hash = "sha256:f4b87665667d4d3e818d70495e832e368f11a1fdc9c2fd8157a7d9e5d5147c5d"}, + {file = "aiohttp_middlewares-2.2.0.tar.gz", hash = "sha256:3967b2a0d17a2c094681e7c2f246977a365479a2820e48f8a01136c910f4aa93"}, +] aiosignal = [ - {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"}, - {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"}, + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, ] alabaster = [ {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, @@ -1845,23 +1956,58 @@ asynctest = [ {file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"}, ] atomicwrites = [] -attrs = [] +attrs = [ + {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, + {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, +] autopep8 = [ {file = "autopep8-1.5.7-py2.py3-none-any.whl", hash = "sha256:aa213493c30dcdac99537249ee65b24af0b2c29f2e83cd8b3f68760441ed0db9"}, {file = "autopep8-1.5.7.tar.gz", hash = "sha256:276ced7e9e3cb22e5d7c14748384a5cf5d9002257c0ed50c0e075b68011bb6d0"}, ] -babel = [] -bcrypt = [] +babel = [ + {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"}, + {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"}, +] +bcrypt = [ + {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"}, + {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"}, + {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"}, + {file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"}, + {file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"}, + {file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"}, +] blessed = [ {file = "blessed-1.19.1-py2.py3-none-any.whl", hash = "sha256:63b8554ae2e0e7f43749b6715c734cc8f3883010a809bf16790102563e6cf25b"}, {file = "blessed-1.19.1.tar.gz", hash = "sha256:9a0d099695bf621d4680dd6c73f6ad547f6a3442fbdbe80c4b1daa1edbc492fc"}, ] cachetools = [] -certifi = [] +certifi = [ + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, +] cffi = [] +cfgv = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] charset-normalizer = [ - {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, - {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, ] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, @@ -1871,17 +2017,96 @@ clique = [ {file = "clique-1.6.1-py2.py3-none-any.whl", hash = "sha256:8619774fa035661928dd8c93cd805acf2d42533ccea1b536c09815ed426c9858"}, {file = "clique-1.6.1.tar.gz", hash = "sha256:90165c1cf162d4dd1baef83ceaa1afc886b453e379094fa5b60ea470d1733e66"}, ] -colorama = [] +colorama = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] commonmark = [ {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coolname = [ - {file = "coolname-1.1.0-py2.py3-none-any.whl", hash = "sha256:e6a83a0ac88640f4f3d2070438dbe112fe80cfebc119c93bd402976ec84c0978"}, - {file = "coolname-1.1.0.tar.gz", hash = "sha256:410fe6ea9999bf96f2856ef0c726d5f38782bbefb7bb1aca0e91e0dc98ed09e3"}, + {file = "coolname-2.1.0-py2.py3-none-any.whl", hash = "sha256:e30a311aa8a1d3fe1a7da290ca65b4ac81927c3e91dcc18f179462e9204f01b0"}, + {file = "coolname-2.1.0.tar.gz", hash = "sha256:8a605be9e48b261ac50e9f258c40adcd4081b9ca0e6f08d39511f77cb2ae55ba"}, +] +coverage = [ + {file = "coverage-7.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f7c51b6074a8a3063c341953dffe48fd6674f8e4b1d3c8aa8a91f58d6e716a8"}, + {file = "coverage-7.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:628f47eaf66727fc986d3b190d6fa32f5e6b7754a243919d28bc0fd7974c449f"}, + {file = "coverage-7.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89d5abf86c104de808108a25d171ad646c07eda96ca76c8b237b94b9c71e518"}, + {file = "coverage-7.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75e43c6f4ea4d122dac389aabdf9d4f0e160770a75e63372f88005d90f5bcc80"}, + {file = "coverage-7.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49da0ff241827ebb52d5d6d5a36d33b455fa5e721d44689c95df99fd8db82437"}, + {file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0bce4ad5bdd0b02e177a085d28d2cea5fc57bb4ba2cead395e763e34cf934eb1"}, + {file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f79691335257d60951638dd43576b9bcd6f52baa5c1c2cd07a509bb003238372"}, + {file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5722269ed05fbdb94eef431787c66b66260ff3125d1a9afcc00facff8c45adf9"}, + {file = "coverage-7.0.3-cp310-cp310-win32.whl", hash = "sha256:bdbda870e0fda7dd0fe7db7135ca226ec4c1ade8aa76e96614829b56ca491012"}, + {file = "coverage-7.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:e56fae4292e216b8deeee38ace84557b9fa85b52db005368a275427cdabb8192"}, + {file = "coverage-7.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b82343a5bc51627b9d606f0b6b6b9551db7b6311a5dd920fa52a94beae2e8959"}, + {file = "coverage-7.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fd0a8aa431f9b7ad9eb8264f55ef83cbb254962af3775092fb6e93890dea9ca2"}, + {file = "coverage-7.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:112cfead1bd22eada8a8db9ed387bd3e8be5528debc42b5d3c1f7da4ffaf9fb5"}, + {file = "coverage-7.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af87e906355fa42447be5c08c5d44e6e1c005bf142f303f726ddf5ed6e0c8a4d"}, + {file = "coverage-7.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f30090e22a301952c5abd0e493a1c8358b4f0b368b49fa3e4568ed3ed68b8d1f"}, + {file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae871d09901911eedda1981ea6fd0f62a999107293cdc4c4fd612321c5b34745"}, + {file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ed7c9debf7bfc63c9b9f8b595409237774ff4b061bf29fba6f53b287a2fdeab9"}, + {file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:13121fa22dcd2c7b19c5161e3fd725692448f05377b788da4502a383573227b3"}, + {file = "coverage-7.0.3-cp311-cp311-win32.whl", hash = "sha256:037b51ee86bc600f99b3b957c20a172431c35c2ef9c1ca34bc813ab5b51fd9f5"}, + {file = "coverage-7.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:25fde928306034e8deecd5fc91a07432dcc282c8acb76749581a28963c9f4f3f"}, + {file = "coverage-7.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7e8b0642c38b3d3b3c01417643ccc645345b03c32a2e84ef93cdd6844d6fe530"}, + {file = "coverage-7.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18b09811f849cc958d23f733a350a66b54a8de3fed1e6128ba55a5c97ffb6f65"}, + {file = "coverage-7.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:349d0b545520e8516f7b4f12373afc705d17d901e1de6a37a20e4ec9332b61f7"}, + {file = "coverage-7.0.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b38813eee5b4739f505d94247604c72eae626d5088a16dd77b08b8b1724ab3"}, + {file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ba9af1218fa01b1f11c72271bc7290b701d11ad4dbc2ae97c445ecacf6858dba"}, + {file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c5648c7eec5cf1ba5db1cf2d6c10036a582d7f09e172990474a122e30c841361"}, + {file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d0df04495b76a885bfef009f45eebe8fe2fbf815ad7a83dabcf5aced62f33162"}, + {file = "coverage-7.0.3-cp37-cp37m-win32.whl", hash = "sha256:af6cef3796b8068713a48dd67d258dc9a6e2ebc3bd4645bfac03a09672fa5d20"}, + {file = "coverage-7.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:62ef3800c4058844e2e3fa35faa9dd0ccde8a8aba6c763aae50342e00d4479d4"}, + {file = "coverage-7.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acef7f3a3825a2d218a03dd02f5f3cc7f27aa31d882dd780191d1ad101120d74"}, + {file = "coverage-7.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a530663a361eb27375cec28aea5cd282089b5e4b022ae451c4c3493b026a68a5"}, + {file = "coverage-7.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c58cd6bb46dcb922e0d5792850aab5964433d511b3a020867650f8d930dde4f4"}, + {file = "coverage-7.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f918e9ef4c98f477a5458238dde2a1643aed956c7213873ab6b6b82e32b8ef61"}, + {file = "coverage-7.0.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b865aa679bee7fbd1c55960940dbd3252621dd81468268786c67122bbd15343"}, + {file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c5d9b480ebae60fc2cbc8d6865194136bc690538fa542ba58726433bed6e04cc"}, + {file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:985ad2af5ec3dbb4fd75d5b0735752c527ad183455520055a08cf8d6794cabfc"}, + {file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ca15308ef722f120967af7474ba6a453e0f5b6f331251e20b8145497cf1bc14a"}, + {file = "coverage-7.0.3-cp38-cp38-win32.whl", hash = "sha256:c1cee10662c25c94415bbb987f2ec0e6ba9e8fce786334b10be7e6a7ab958f69"}, + {file = "coverage-7.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:44d6a556de4418f1f3bfd57094b8c49f0408df5a433cf0d253eeb3075261c762"}, + {file = "coverage-7.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e6dcc70a25cb95df0ae33dfc701de9b09c37f7dd9f00394d684a5b57257f8246"}, + {file = "coverage-7.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf76d79dfaea802f0f28f50153ffbc1a74ae1ee73e480baeda410b4f3e7ab25f"}, + {file = "coverage-7.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88834e5d56d01c141c29deedacba5773fe0bed900b1edc957595a8a6c0da1c3c"}, + {file = "coverage-7.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef001a60e888f8741e42e5aa79ae55c91be73761e4df5e806efca1ddd62fd400"}, + {file = "coverage-7.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4959dc506be74e4963bd2c42f7b87d8e4b289891201e19ec551e64c6aa5441f8"}, + {file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b791beb17b32ac019a78cfbe6184f992b6273fdca31145b928ad2099435e2fcb"}, + {file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b07651e3b9af8f1a092861d88b4c74d913634a7f1f2280fca0ad041ad84e9e96"}, + {file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:55e46fa4168ccb7497c9be78627fcb147e06f474f846a10d55feeb5108a24ef0"}, + {file = "coverage-7.0.3-cp39-cp39-win32.whl", hash = "sha256:e3f1cd1cd65695b1540b3cf7828d05b3515974a9d7c7530f762ac40f58a18161"}, + {file = "coverage-7.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:d8249666c23683f74f8f93aeaa8794ac87cc61c40ff70374a825f3352a4371dc"}, + {file = "coverage-7.0.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:b1ffc8f58b81baed3f8962e28c30d99442079b82ce1ec836a1f67c0accad91c1"}, + {file = "coverage-7.0.3.tar.gz", hash = "sha256:d5be4e93acce64f516bf4fd239c0e6118fc913c93fa1a3f52d15bdcc60d97b2d"}, +] +cryptography = [ + {file = "cryptography-39.0.0-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52a1a6f81e738d07f43dab57831c29e57d21c81a942f4602fac7ee21b27f288"}, + {file = "cryptography-39.0.0-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:80ee674c08aaef194bc4627b7f2956e5ba7ef29c3cc3ca488cf15854838a8f72"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:887cbc1ea60786e534b00ba8b04d1095f4272d380ebd5f7a7eb4cc274710fad9"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f97109336df5c178ee7c9c711b264c502b905c2d2a29ace99ed761533a3460f"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a6915075c6d3a5e1215eab5d99bcec0da26036ff2102a1038401d6ef5bef25b"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:76c24dd4fd196a80f9f2f5405a778a8ca132f16b10af113474005635fe7e066c"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:bae6c7f4a36a25291b619ad064a30a07110a805d08dc89984f4f441f6c1f3f96"}, + {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:875aea1039d78557c7c6b4db2fe0e9d2413439f4676310a5f269dd342ca7a717"}, + {file = "cryptography-39.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f6c0db08d81ead9576c4d94bbb27aed8d7a430fa27890f39084c2d0e2ec6b0df"}, + {file = "cryptography-39.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f3ed2d864a2fa1666e749fe52fb8e23d8e06b8012e8bd8147c73797c506e86f1"}, + {file = "cryptography-39.0.0-cp36-abi3-win32.whl", hash = "sha256:f671c1bb0d6088e94d61d80c606d65baacc0d374e67bf895148883461cd848de"}, + {file = "cryptography-39.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:e324de6972b151f99dc078defe8fb1b0a82c6498e37bff335f5bc6b1e3ab5a1e"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:754978da4d0457e7ca176f58c57b1f9de6556591c19b25b8bcce3c77d314f5eb"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ee1fd0de9851ff32dbbb9362a4d833b579b4a6cc96883e8e6d2ff2a6bc7104f"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:fec8b932f51ae245121c4671b4bbc030880f363354b2f0e0bd1366017d891458"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:407cec680e811b4fc829de966f88a7c62a596faa250fc1a4b520a0355b9bc190"}, + {file = "cryptography-39.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7dacfdeee048814563eaaec7c4743c8aea529fe3dd53127313a792f0dadc1773"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad04f413436b0781f20c52a661660f1e23bcd89a0e9bb1d6d20822d048cf2856"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50386acb40fbabbceeb2986332f0287f50f29ccf1497bae31cf5c3e7b4f4b34f"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:e5d71c5d5bd5b5c3eebcf7c5c2bb332d62ec68921a8c593bea8c394911a005ce"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:844ad4d7c3850081dffba91cdd91950038ee4ac525c575509a42d3fc806b83c8"}, + {file = "cryptography-39.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e0a05aee6a82d944f9b4edd6a001178787d1546ec7c6223ee9a848a7ade92e39"}, + {file = "cryptography-39.0.0.tar.gz", hash = "sha256:f964c7dcf7802d133e8dbd1565914fa0194f9d683d82411989889ecd701e8adf"}, ] -coverage = [] -cryptography = [] cx-freeze = [ {file = "cx_Freeze-6.9-cp310-cp310-win32.whl", hash = "sha256:776d4fb68a4831691acbd3c374362b9b48ce2e568514a73c3d4cb14d5dcf1470"}, {file = "cx_Freeze-6.9-cp310-cp310-win_amd64.whl", hash = "sha256:243f36d35a034a409cd6247d8cb5d1fbfd7374e3e668e813d0811f64d6bd5ed3"}, @@ -1896,22 +2121,37 @@ cx-freeze = [ {file = "cx_Freeze-6.9.tar.gz", hash = "sha256:673aa3199af2ef87fc03a43a30e5d78b27ced2cedde925da89c55b5657da267b"}, ] cx-logging = [ - {file = "cx_Logging-3.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:9fcd297e5c51470521c47eff0f86ba844aeca6be97e13c3e2114ebdf03fa3c96"}, - {file = "cx_Logging-3.0-cp36-cp36m-win32.whl", hash = "sha256:0df4be47c5022cc54316949e283403214568ef599817ced0c0972183d6d4fabb"}, - {file = "cx_Logging-3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:203ca92ee7c15d5dfe1fcdfcef7b39d0123eba5c6d8c2388b6e7db6b961a5362"}, - {file = "cx_Logging-3.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:20daa71b2a30f61d09bcf55dbda002c10f0c7c691f53cb393fc6485410fa2484"}, - {file = "cx_Logging-3.0-cp37-cp37m-win32.whl", hash = "sha256:5be5f905e8d34a3326e28d428674cdc2d57912fdf6e25b8676d63f76294eb4e0"}, - {file = "cx_Logging-3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:04e4b61e2636dc8ae135937655af6626362aefc7f6175e86888a244b61001823"}, - {file = "cx_Logging-3.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1bf0ebc79a7baa331c7deaf57088c234b82710286dfad453ff0c55eee0122b72"}, - {file = "cx_Logging-3.0-cp38-cp38-win32.whl", hash = "sha256:d98a59a47e99fa430b3f6d2a979e27509852d2c43e204f43bd0168e7ec97f469"}, - {file = "cx_Logging-3.0-cp38-cp38-win_amd64.whl", hash = "sha256:bb2e91019e5905415f795eef994de60ace5ae186fc4fe3d358e2d8feebb24992"}, - {file = "cx_Logging-3.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b6f4a9b750e02a180517f779d174a1c7db651981cd37e5623235b87da9774dfd"}, - {file = "cx_Logging-3.0-cp39-cp39-win32.whl", hash = "sha256:e7cca28e8ee4082654b6062cc4d06f83d48f1a7e2d152bab020c9e3e373afb90"}, - {file = "cx_Logging-3.0-cp39-cp39-win_amd64.whl", hash = "sha256:302e9c4f65a936c288a4fa59a90e7e142d9ef994aa29676731acafdcccdbb3f5"}, - {file = "cx_Logging-3.0.tar.gz", hash = "sha256:ba8a7465facf7b98d8f494030fb481a2e8aeee29dc191e10383bb54ed42bdb34"}, + {file = "cx_Logging-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d6aee2d91d4abeafa8ae1a5cacdcc363031ab6e69a3c5b221b294f5b94b0830"}, + {file = "cx_Logging-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7f2d686ca7347e14d248e4f57279b9340b305f86888806313111ab7964835f4"}, + {file = "cx_Logging-3.1.0-cp310-cp310-win32.whl", hash = "sha256:93ee6c9109d129f63344aa9da10dfc6c0d2ac3b2656599a4f884bf482c1fd2f6"}, + {file = "cx_Logging-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:7d69b2986e53f8f14d6fcd1614472f378edf63eea6c71c04d42cb215f7012717"}, + {file = "cx_Logging-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e16a66e8ce16b28a79c9dcf9bda2f36297bd552ec7d9a80cc70e19970d49460"}, + {file = "cx_Logging-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:564bea49c30342478ff2301c39a61c47c926e01146052b2a505ac11896ef51d2"}, + {file = "cx_Logging-3.1.0-cp311-cp311-win32.whl", hash = "sha256:cfd260cd431f2087cac2a9bfb738c2e428eb30e2b85ba0e0bce8dde2cb4843eb"}, + {file = "cx_Logging-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:c61388bd9410817839187dab602f47d307f3f58df2dd11fb698cd321b8b48985"}, + {file = "cx_Logging-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1937991c2daab59ced3bf8f52b1052b0157c0c30f229aa87bd384ab18dc8d1f3"}, + {file = "cx_Logging-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8129e2d6bbff03fa7b09e9b587a5aed178fa16032508bae0f4db7e933fb43d08"}, + {file = "cx_Logging-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:80aac0557464995780769535edf8057bab79a54cb4126363a7134b4ae38d25a3"}, + {file = "cx_Logging-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ce9a37ab15890a87d144a7206c30d16192b67e63e8e52f02c579daa72a10767e"}, + {file = "cx_Logging-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8040a77b922eacd342d2dc0804a06425d772cf9cde61dd4c01e61aaaf9189f9f"}, + {file = "cx_Logging-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3accfa4ae945c3f65d7fc830058272e263b27e09672539d8dc2ed190a07be99e"}, + {file = "cx_Logging-3.1.0-cp38-cp38-win32.whl", hash = "sha256:ae6d01072625de14584e79af4aade249b3b7080e90a3df6b47ada72b0ecd8b79"}, + {file = "cx_Logging-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:10fca1790e3467548472987e1a39379a96b93da09bdc1b64b3075605d473aaf6"}, + {file = "cx_Logging-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78b82737e589d5805b044a64afa8d2782a388a42898af084c6ab76153bc531fb"}, + {file = "cx_Logging-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82fc9cd57a4c151856759d76b9e44700913de60d6b97d661000577dad89f383b"}, + {file = "cx_Logging-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a98781f59652c58b0648a835b5f5a9cfcdc90957283818d1babf98aed3a5e28f"}, + {file = "cx_Logging-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a1548d8339baf54c7f1f372e68d381be7ce3e9506f2aa0987e88670a446a773"}, + {file = "cx_Logging-3.1.0.tar.gz", hash = "sha256:8a06834d8527aa904a68b25c9c1a5fa09f0dfdc94dbd9f86b81cd8d2f7a0e487"}, ] deprecated = [] -dill = [] +dill = [ + {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, + {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, +] +distlib = [ + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, +] dnspython = [ {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, @@ -1920,55 +2160,159 @@ docutils = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] -dropbox = [] +dropbox = [ + {file = "dropbox-11.36.0-py2-none-any.whl", hash = "sha256:91d26a47a6db294e5d787d233e70d8f785efee6d456564588e81a6a2ac4c550b"}, + {file = "dropbox-11.36.0-py3-none-any.whl", hash = "sha256:5d36e3b08c2e542f31469d82031be2606963f774b2f1105e3aa11c9913c67697"}, + {file = "dropbox-11.36.0.tar.gz", hash = "sha256:830ce522d8bc3905b4a99b67dc009aa9542550d1de9fa1743c1927de70888b47"}, +] enlighten = [ - {file = "enlighten-1.10.2-py2.py3-none-any.whl", hash = "sha256:b237fe562b320bf9f1d4bb76d0c98e0daf914372a76ab87c35cd02f57aa9d8c1"}, - {file = "enlighten-1.10.2.tar.gz", hash = "sha256:7a5b83cd0f4d095e59d80c648ebb5f7ffca0cd8bcf7ae6639828ee1ad000632a"}, + {file = "enlighten-1.11.1-py2.py3-none-any.whl", hash = "sha256:e825eb534ca80778bb7d46e5581527b2a6fae559b6cf09e290a7952c6e11961e"}, + {file = "enlighten-1.11.1.tar.gz", hash = "sha256:57abd98a3d3f83484ef9f91f9255f4d23c8b3097ecdb647c7b9b0049d600b7f8"}, ] evdev = [] +filelock = [ + {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"}, + {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"}, +] flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, ] -frozenlist = [] +frozenlist = [ + {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4"}, + {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0"}, + {file = "frozenlist-1.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530"}, + {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7"}, + {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99"}, + {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483"}, + {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd"}, + {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf"}, + {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816"}, + {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0"}, + {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce"}, + {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f"}, + {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420"}, + {file = "frozenlist-1.3.3-cp310-cp310-win32.whl", hash = "sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642"}, + {file = "frozenlist-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1"}, + {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7"}, + {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678"}, + {file = "frozenlist-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6"}, + {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8"}, + {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb"}, + {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91"}, + {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b"}, + {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4"}, + {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48"}, + {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d"}, + {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6"}, + {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4"}, + {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81"}, + {file = "frozenlist-1.3.3-cp311-cp311-win32.whl", hash = "sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8"}, + {file = "frozenlist-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32"}, + {file = "frozenlist-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332"}, + {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27"}, + {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d"}, + {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e"}, + {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d"}, + {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c"}, + {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56"}, + {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420"}, + {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e"}, + {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb"}, + {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401"}, + {file = "frozenlist-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a"}, + {file = "frozenlist-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411"}, + {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a"}, + {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5"}, + {file = "frozenlist-1.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e"}, + {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c"}, + {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba"}, + {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703"}, + {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2"}, + {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448"}, + {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4"}, + {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649"}, + {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842"}, + {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13"}, + {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3"}, + {file = "frozenlist-1.3.3-cp38-cp38-win32.whl", hash = "sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b"}, + {file = "frozenlist-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef"}, + {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf"}, + {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1"}, + {file = "frozenlist-1.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0"}, + {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d"}, + {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936"}, + {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5"}, + {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b"}, + {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669"}, + {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb"}, + {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784"}, + {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d"}, + {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab"}, + {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1"}, + {file = "frozenlist-1.3.3-cp39-cp39-win32.whl", hash = "sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38"}, + {file = "frozenlist-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9"}, + {file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"}, +] ftrack-python-api = [] future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, ] -gazu = [] +gazu = [ + {file = "gazu-0.8.34-py2.py3-none-any.whl", hash = "sha256:a78a8c5e61108aeaab6185646af78b0402dbdb29097e8ba5882bd55410f38c4b"}, +] gitdb = [ - {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, - {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, + {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, + {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, ] gitpython = [ - {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, - {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, + {file = "GitPython-3.1.30-py3-none-any.whl", hash = "sha256:cd455b0000615c60e286208ba540271af9fe531fa6a87cc590a7298785ab2882"}, + {file = "GitPython-3.1.30.tar.gz", hash = "sha256:769c2d83e13f5d938b7688479da374c4e3d49f71549aaf462b646db9602ea6f8"}, +] +google-api-core = [ + {file = "google-api-core-2.11.0.tar.gz", hash = "sha256:4b9bb5d5a380a0befa0573b302651b8a9a89262c1730e37bf423cec511804c22"}, + {file = "google_api_core-2.11.0-py3-none-any.whl", hash = "sha256:ce222e27b0de0d7bc63eb043b956996d6dccab14cc3b690aaea91c9cc99dc16e"}, ] -google-api-core = [] google-api-python-client = [ {file = "google-api-python-client-1.12.11.tar.gz", hash = "sha256:1b4bd42a46321e13c0542a9e4d96fa05d73626f07b39f83a73a947d70ca706a9"}, {file = "google_api_python_client-1.12.11-py2.py3-none-any.whl", hash = "sha256:7e0a1a265c8d3088ee1987778c72683fcb376e32bada8d7767162bd9c503fd9b"}, ] -google-auth = [] +google-auth = [ + {file = "google-auth-2.15.0.tar.gz", hash = "sha256:72f12a6cfc968d754d7bdab369c5c5c16032106e52d32c6dfd8484e4c01a6d1f"}, + {file = "google_auth-2.15.0-py2.py3-none-any.whl", hash = "sha256:6897b93556d8d807ad70701bb89f000183aea366ca7ed94680828b37437a4994"}, +] google-auth-httplib2 = [ {file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"}, {file = "google_auth_httplib2-0.1.0-py2.py3-none-any.whl", hash = "sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10"}, ] -googleapis-common-protos = [] -httplib2 = [ - {file = "httplib2-0.20.4-py3-none-any.whl", hash = "sha256:8b6a905cb1c79eefd03f8669fd993c36dc341f7c558f056cb5a33b5c2f458543"}, - {file = "httplib2-0.20.4.tar.gz", hash = "sha256:58a98e45b4b1a48273073f905d2961666ecf0fbac4250ea5b47aef259eb5c585"}, +googleapis-common-protos = [ + {file = "googleapis-common-protos-1.57.1.tar.gz", hash = "sha256:e877f2f041b640b4888b6917dde4f44515ab938bf744c4dbc06f11f0e8ed56b5"}, + {file = "googleapis_common_protos-1.57.1-py2.py3-none-any.whl", hash = "sha256:2672d6b3a7b6188b70a5a4c70def7ddbb9000852dfbf49daf52fc7306c09db0c"}, +] +httplib2 = [ + {file = "httplib2-0.21.0-py3-none-any.whl", hash = "sha256:987c8bb3eb82d3fa60c68699510a692aa2ad9c4bd4f123e51dfb1488c14cdd01"}, + {file = "httplib2-0.21.0.tar.gz", hash = "sha256:fc144f091c7286b82bec71bdbd9b27323ba709cc612568d3000893bfd9cb4b34"}, +] +identify = [ + {file = "identify-2.5.12-py2.py3-none-any.whl", hash = "sha256:e8a400c3062d980243d27ce10455a52832205649bbcaf27ffddb3dfaaf477bad"}, + {file = "identify-2.5.12.tar.gz", hash = "sha256:0bc96b09c838310b6fcfcc61f78a981ea07f94836ef6ef553da5bb5d4745d662"}, +] +idna = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] -idna = [] imagesize = [] -importlib-metadata = [] +importlib-metadata = [ + {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, + {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, +] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, + {file = "isort-5.11.4-py3-none-any.whl", hash = "sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b"}, + {file = "isort-5.11.4.tar.gz", hash = "sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6"}, ] jedi = [ {file = "jedi-0.13.3-py2.py3-none-any.whl", hash = "sha256:2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c"}, @@ -1989,43 +2333,42 @@ keyring = [ {file = "keyring-22.4.0.tar.gz", hash = "sha256:d981e02d134cc3d636a716fbc3ca967bc9609bae5dc21b0063e4409355993ddf"}, ] lazy-object-proxy = [ - {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, - {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, + {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, ] log4mongo = [ {file = "log4mongo-1.7.0.tar.gz", hash = "sha256:dc374617206162a0b14167fbb5feac01dbef587539a235dadba6200362984a68"}, @@ -2071,72 +2414,94 @@ mccabe = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] multidict = [ - {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, - {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, - {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"}, - {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"}, - {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"}, - {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"}, - {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"}, - {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"}, - {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"}, - {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"}, - {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"}, - {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, - {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, + {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, + {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, + {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, + {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, + {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, + {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, + {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, + {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, + {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, + {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, + {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, + {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, +] +nodeenv = [ + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, ] opentimelineio = [] packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, + {file = "packaging-22.0-py3-none-any.whl", hash = "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3"}, + {file = "packaging-22.0.tar.gz", hash = "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3"}, +] +paramiko = [ + {file = "paramiko-2.12.0-py2.py3-none-any.whl", hash = "sha256:b2df1a6325f6996ef55a8789d0462f5b502ea83b3c990cbb5bbe57345c6812c4"}, + {file = "paramiko-2.12.0.tar.gz", hash = "sha256:376885c05c5d6aa6e1f4608aac2a6b5b0548b1add40274477324605903d9cd49"}, ] -paramiko = [] parso = [ {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, @@ -2145,8 +2510,75 @@ pathlib2 = [ {file = "pathlib2-2.3.7.post1-py2.py3-none-any.whl", hash = "sha256:5266a0fd000452f1b3467d782f079a4343c63aaa119221fbdc4e39577489ca5b"}, {file = "pathlib2-2.3.7.post1.tar.gz", hash = "sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641"}, ] -pillow = [] -platformdirs = [] +pillow = [ + {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, + {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, + {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, + {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, + {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, + {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, + {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, + {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, + {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, + {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, + {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, + {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, + {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, + {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, + {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, + {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, + {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, + {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, + {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, + {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, + {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, + {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, + {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, + {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, + {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, + {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, + {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, + {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, +] +platformdirs = [ + {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, + {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, +] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, @@ -2155,11 +2587,30 @@ ply = [ {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, ] -prefixed = [ - {file = "prefixed-0.3.2-py2.py3-none-any.whl", hash = "sha256:5e107306462d63f2f03c529dbf11b0026fdfec621a9a008ca639d71de22995c3"}, - {file = "prefixed-0.3.2.tar.gz", hash = "sha256:ca48277ba5fa8346dd4b760847da930c7b84416387c39e93affef086add2c029"}, +pre-commit = [ + {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, + {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, +] +prefixed = [ + {file = "prefixed-0.5.0-py2.py3-none-any.whl", hash = "sha256:debab03014863087eb013750a2e71daa5f6a295cee46b44ba1b90d7262c1b92d"}, + {file = "prefixed-0.5.0.tar.gz", hash = "sha256:b134d734136250b17b68eede65a3370fab0134412cb66bc8be3568ff05bdf8e4"}, +] +protobuf = [ + {file = "protobuf-4.21.12-cp310-abi3-win32.whl", hash = "sha256:b135410244ebe777db80298297a97fbb4c862c881b4403b71bac9d4107d61fd1"}, + {file = "protobuf-4.21.12-cp310-abi3-win_amd64.whl", hash = "sha256:89f9149e4a0169cddfc44c74f230d7743002e3aa0b9472d8c28f0388102fc4c2"}, + {file = "protobuf-4.21.12-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:299ea899484ee6f44604deb71f424234f654606b983cb496ea2a53e3c63ab791"}, + {file = "protobuf-4.21.12-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:d1736130bce8cf131ac7957fa26880ca19227d4ad68b4888b3be0dea1f95df97"}, + {file = "protobuf-4.21.12-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:78a28c9fa223998472886c77042e9b9afb6fe4242bd2a2a5aced88e3f4422aa7"}, + {file = "protobuf-4.21.12-cp37-cp37m-win32.whl", hash = "sha256:3d164928ff0727d97022957c2b849250ca0e64777ee31efd7d6de2e07c494717"}, + {file = "protobuf-4.21.12-cp37-cp37m-win_amd64.whl", hash = "sha256:f45460f9ee70a0ec1b6694c6e4e348ad2019275680bd68a1d9314b8c7e01e574"}, + {file = "protobuf-4.21.12-cp38-cp38-win32.whl", hash = "sha256:6ab80df09e3208f742c98443b6166bcb70d65f52cfeb67357d52032ea1ae9bec"}, + {file = "protobuf-4.21.12-cp38-cp38-win_amd64.whl", hash = "sha256:1f22ac0ca65bb70a876060d96d914dae09ac98d114294f77584b0d2644fa9c30"}, + {file = "protobuf-4.21.12-cp39-cp39-win32.whl", hash = "sha256:27f4d15021da6d2b706ddc3860fac0a5ddaba34ab679dc182b60a8bb4e1121cc"}, + {file = "protobuf-4.21.12-cp39-cp39-win_amd64.whl", hash = "sha256:237216c3326d46808a9f7c26fd1bd4b20015fb6867dc5d263a493ef9a539293b"}, + {file = "protobuf-4.21.12-py2.py3-none-any.whl", hash = "sha256:a53fd3f03e578553623272dc46ac2f189de23862e68565e83dde203d41b76fc5"}, + {file = "protobuf-4.21.12-py3-none-any.whl", hash = "sha256:b98d0148f84e3a3c569e19f52103ca1feacdac0d2df8d6533cf983d1fda28462"}, + {file = "protobuf-4.21.12.tar.gz", hash = "sha256:7cd532c4566d0e6feafecc1059d04c7915aec8e182d1cf7adee8b24ef1e2e6ab"}, ] -protobuf = [] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, @@ -2218,116 +2669,122 @@ pyflakes = [ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] -pygments = [] +pygments = [ + {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, + {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, +] pylint = [] pymongo = [ - {file = "pymongo-3.12.3-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:c164eda0be9048f83c24b9b2656900041e069ddf72de81c17d874d0c32f6079f"}, - {file = "pymongo-3.12.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:a055d29f1302892a9389a382bed10a3f77708bcf3e49bfb76f7712fa5f391cc6"}, - {file = "pymongo-3.12.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8c7ad5cab282f53b9d78d51504330d1c88c83fbe187e472c07e6908a0293142e"}, - {file = "pymongo-3.12.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a766157b195a897c64945d4ff87b050bb0e763bb78f3964e996378621c703b00"}, - {file = "pymongo-3.12.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c8d6bf6fcd42cde2f02efb8126812a010c297eacefcd090a609639d2aeda6185"}, - {file = "pymongo-3.12.3-cp27-cp27m-win32.whl", hash = "sha256:5fdffb0cfeb4dc8646a5381d32ec981ae8472f29c695bf09e8f7a8edb2db12ca"}, - {file = "pymongo-3.12.3-cp27-cp27m-win_amd64.whl", hash = "sha256:648fcfd8e019b122b7be0e26830a3a2224d57c3e934f19c1e53a77b8380e6675"}, - {file = "pymongo-3.12.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3f0ac6e0203bd88863649e6ed9c7cfe53afab304bc8225f2597c4c0a74e4d1f0"}, - {file = "pymongo-3.12.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:71c0db2c313ea8a80825fb61b7826b8015874aec29ee6364ade5cb774fe4511b"}, - {file = "pymongo-3.12.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5b779e87300635b8075e8d5cfd4fdf7f46078cd7610c381d956bca5556bb8f97"}, - {file = "pymongo-3.12.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:351a2efe1c9566c348ad0076f4bf541f4905a0ebe2d271f112f60852575f3c16"}, - {file = "pymongo-3.12.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0a02313e71b7c370c43056f6b16c45effbb2d29a44d24403a3d5ba6ed322fa3f"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux1_i686.whl", hash = "sha256:d3082e5c4d7b388792124f5e805b469109e58f1ab1eb1fbd8b998e8ab766ffb7"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:514e78d20d8382d5b97f32b20c83d1d0452c302c9a135f0a9022236eb9940fda"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:b1b5be40ebf52c3c67ee547e2c4435ed5bc6352f38d23e394520b686641a6be4"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:58db209da08a502ce6948841d522dcec80921d714024354153d00b054571993c"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:5296e5e69243ffd76bd919854c4da6630ae52e46175c804bc4c0e050d937b705"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:51d1d061df3995c2332ae78f036492cc188cb3da8ef122caeab3631a67bb477e"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:463b974b7f49d65a16ca1435bc1c25a681bb7d630509dd23b2e819ed36da0b7f"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e099b79ccf7c40f18b149a64d3d10639980035f9ceb223169dd806ff1bb0d9cc"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27e5ea64332385385b75414888ce9d1a9806be8616d7cef4ef409f4f256c6d06"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed7d11330e443aeecab23866055e08a5a536c95d2c25333aeb441af2dbac38d2"}, - {file = "pymongo-3.12.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93111fd4e08fa889c126aa8baf5c009a941880a539c87672e04583286517450a"}, - {file = "pymongo-3.12.3-cp310-cp310-win32.whl", hash = "sha256:2301051701b27aff2cbdf83fae22b7ca883c9563dfd088033267291b46196643"}, - {file = "pymongo-3.12.3-cp310-cp310-win_amd64.whl", hash = "sha256:c7e8221278e5f9e2b6d3893cfc3a3e46c017161a57bb0e6f244826e4cee97916"}, - {file = "pymongo-3.12.3-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:7b4a9fcd95e978cd3c96cdc2096aa54705266551422cf0883c12a4044def31c6"}, - {file = "pymongo-3.12.3-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:06b64cdf5121f86b78a84e61b8f899b6988732a8d304b503ea1f94a676221c06"}, - {file = "pymongo-3.12.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:c8f7dd025cb0bf19e2f60a64dfc24b513c8330e0cfe4a34ccf941eafd6194d9e"}, - {file = "pymongo-3.12.3-cp34-cp34m-win32.whl", hash = "sha256:ab23b0545ec71ea346bf50a5d376d674f56205b729980eaa62cdb7871805014b"}, - {file = "pymongo-3.12.3-cp34-cp34m-win_amd64.whl", hash = "sha256:1b5cb75d2642ff7db823f509641f143f752c0d1ab03166cafea1e42e50469834"}, - {file = "pymongo-3.12.3-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:fc2048d13ff427605fea328cbe5369dce549b8c7657b0e22051a5b8831170af6"}, - {file = "pymongo-3.12.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c5f83bb59d0ff60c6fdb1f8a7b0288fbc4640b1f0fd56f5ae2387749c35d34e3"}, - {file = "pymongo-3.12.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6632b1c63d58cddc72f43ab9f17267354ddce563dd5e11eadabd222dcc808808"}, - {file = "pymongo-3.12.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fedad05147b40ff8a93fcd016c421e6c159f149a2a481cfa0b94bfa3e473bab"}, - {file = "pymongo-3.12.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:208a61db8b8b647fb5b1ff3b52b4ed6dbced01eac3b61009958adb203596ee99"}, - {file = "pymongo-3.12.3-cp35-cp35m-win32.whl", hash = "sha256:3100a2352bdded6232b385ceda0c0a4624598c517d52c2d8cf014b7abbebd84d"}, - {file = "pymongo-3.12.3-cp35-cp35m-win_amd64.whl", hash = "sha256:3492ae1f97209c66af70e863e6420e6301cecb0a51a5efa701058aa73a8ca29e"}, - {file = "pymongo-3.12.3-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:87e18f29bac4a6be76a30e74de9c9005475e27100acf0830679420ce1fd9a6fd"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b3e08aef4ea05afbc0a70cd23c13684e7f5e074f02450964ec5cfa1c759d33d2"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e66b3c9f8b89d4fd58a59c04fdbf10602a17c914fbaaa5e6ea593f1d54b06362"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5d67dbc8da2dac1644d71c1839d12d12aa333e266a9964d5b1a49feed036bc94"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:a351986d6c9006308f163c359ced40f80b6cffb42069f3e569b979829951038d"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:5296669bff390135528001b4e48d33a7acaffcd361d98659628ece7f282f11aa"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:9d5b66d457d2c5739c184a777455c8fde7ab3600a56d8bbebecf64f7c55169e1"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:1c771f1a8b3cd2d697baaf57e9cfa4ae42371cacfbea42ea01d9577c06d92f96"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81a3ebc33b1367f301d1c8eda57eec4868e951504986d5d3fe437479dcdac5b2"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cf113a46d81cff0559d57aa66ffa473d57d1a9496f97426318b6b5b14fdec1c"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64b9122be1c404ce4eb367ad609b590394587a676d84bfed8e03c3ce76d70560"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c6c71e198b36f0f0dfe354f06d3655ecfa30d69493a1da125a9a54668aad652"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33ab8c031f788609924e329003088831045f683931932a52a361d4a955b7dce2"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e2b4c95c47fb81b19ea77dc1c50d23af3eba87c9628fcc2e03d44124a3d336ea"}, - {file = "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4e0a3ea7fd01cf0a36509f320226bd8491e0f448f00b8cb89f601c109f6874e1"}, - {file = "pymongo-3.12.3-cp36-cp36m-win32.whl", hash = "sha256:dfec57f15f53d677b8e4535695ff3f37df7f8fe431f2efa8c3c8c4025b53d1eb"}, - {file = "pymongo-3.12.3-cp36-cp36m-win_amd64.whl", hash = "sha256:c22591cff80188dd8543be0b559d0c807f7288bd353dc0bcfe539b4588b3a5cd"}, - {file = "pymongo-3.12.3-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:7738147cd9dbd6d18d5593b3491b4620e13b61de975fd737283e4ad6c255c273"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:be1f10145f7ea76e3e836fdc5c8429c605675bdcddb0bca9725ee6e26874c00c"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:295a5beaecb7bf054c1c6a28749ed72b19f4d4b61edcd8a0815d892424baf780"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:320f8734553c50cffe8a8e1ae36dfc7d7be1941c047489db20a814d2a170d7b5"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:5d20072d81cbfdd8e15e6a0c91fc7e3a4948c71e0adebfc67d3b4bcbe8602711"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:2c46a0afef69d61938a6fe32c3afd75b91dec3ab3056085dc72abbeedcc94166"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:5f530f35e1a57d4360eddcbed6945aecdaee2a491cd3f17025e7b5f2eea88ee7"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:6526933760ee1e6090db808f1690a111ec409699c1990efc96f134d26925c37f"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95d15cf81cd2fb926f2a6151a9f94c7aacc102b415e72bc0e040e29332b6731c"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d52a70350ec3dfc39b513df12b03b7f4c8f8ec6873bbf958299999db7b05eb1"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9252c991e8176b5a2fa574c5ab9a841679e315f6e576eb7cf0bd958f3e39b0ad"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:145d78c345a38011497e55aff22c0f8edd40ee676a6810f7e69563d68a125e83"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8e0a086dbbee406cc6f603931dfe54d1cb2fba585758e06a2de01037784b737"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f6d5443104f89a840250087863c91484a72f254574848e951d1bdd7d8b2ce7c9"}, - {file = "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6f93dbfa5a461107bc3f5026e0d5180499e13379e9404f07a9f79eb5e9e1303d"}, - {file = "pymongo-3.12.3-cp37-cp37m-win32.whl", hash = "sha256:c9d212e2af72d5c8d082775a43eb726520e95bf1c84826440f74225843975136"}, - {file = "pymongo-3.12.3-cp37-cp37m-win_amd64.whl", hash = "sha256:320a1fe403dd83a35709fcf01083d14bc1462e9789b711201349a9158db3a87e"}, - {file = "pymongo-3.12.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a1ba93be779a9b8e5e44f5c133dc1db4313661cead8a2fd27661e6cb8d942ee9"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4294f2c1cd069b793e31c2e6d7ac44b121cf7cedccd03ebcc30f3fc3417b314a"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:845b178bd127bb074835d2eac635b980c58ec5e700ebadc8355062df708d5a71"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:176fdca18391e1206c32fb1d8265628a84d28333c20ad19468d91e3e98312cd1"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:28bfd5244d32faf3e49b5a8d1fab0631e922c26e8add089312e4be19fb05af50"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:f38b35ecd2628bf0267761ed659e48af7e620a7fcccfccf5774e7308fb18325c"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:cebb3d8bcac4a6b48be65ebbc5c9881ed4a738e27bb96c86d9d7580a1fb09e05"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:80710d7591d579442c67a3bc7ae9dcba9ff95ea8414ac98001198d894fc4ff46"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d7baa847383b9814de640c6f1a8553d125ec65e2761ad146ea2e75a7ad197c"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:602284e652bb56ca8760f8e88a5280636c5b63d7946fca1c2fe0f83c37dffc64"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2d763d05ec7211313a06e8571236017d3e61d5fef97fcf34ec4b36c0b6556"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a6e4dccae8ef5dd76052647d78f02d5d0ffaff1856277d951666c54aeba3ad2"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1fc4d3985868860b6585376e511bb32403c5ffb58b0ed913496c27fd791deea"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e4e5d163e6644c2bc84dd9f67bfa89288c23af26983d08fefcc2cbc22f6e57e6"}, - {file = "pymongo-3.12.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8d92c6bb9174d47c2257528f64645a00bbc6324a9ff45a626192797aff01dc14"}, - {file = "pymongo-3.12.3-cp38-cp38-win32.whl", hash = "sha256:b0db9a4691074c347f5d7ee830ab3529bc5ad860939de21c1f9c403daf1eda9a"}, - {file = "pymongo-3.12.3-cp38-cp38-win_amd64.whl", hash = "sha256:d81047341ab56061aa4b6823c54d4632579c3b16e675089e8f520e9b918a133b"}, - {file = "pymongo-3.12.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07398d8a03545b98282f459f2603a6bb271f4448d484ed7f411121a519a7ea48"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b7df0d99e189b7027d417d4bfd9b8c53c9c7ed5a0a1495d26a6f547d820eca88"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:a283425e6a474facd73072d8968812d1d9058490a5781e022ccf8895500b83ce"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:2577b8161eeae4dd376d13100b2137d883c10bb457dd08935f60c9f9d4b5c5f6"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:517b09b1dd842390a965a896d1327c55dfe78199c9f5840595d40facbcd81854"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:2567885ff0c8c7c0887ba6cefe4ae4af96364a66a7069f924ce0cd12eb971d04"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:71c5c200fd37a5322706080b09c3ec8907cf01c377a7187f354fc9e9e13abc73"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:14dee106a10b77224bba5efeeb6aee025aabe88eb87a2b850c46d3ee55bdab4a"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f340a2a908644ea6cccd399be0fb308c66e05d2800107345f9f0f0d59e1731c4"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b4c535f524c9d8c86c3afd71d199025daa070859a2bdaf94a298120b0de16db"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8455176fd1b86de97d859fed4ae0ef867bf998581f584c7a1a591246dfec330f"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf254a1a95e95fdf4eaa25faa1ea450a6533ed7a997f9f8e49ab971b61ea514d"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8a3540e21213cb8ce232e68a7d0ee49cdd35194856c50b8bd87eeb572fadd42"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0e7a5d0b9077e8c3e57727f797ee8adf12e1d5e7534642230d98980d160d1320"}, - {file = "pymongo-3.12.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0be605bfb8461384a4cb81e80f51eb5ca1b89851f2d0e69a75458c788a7263a4"}, - {file = "pymongo-3.12.3-cp39-cp39-win32.whl", hash = "sha256:2157d68f85c28688e8b723bbe70c8013e0aba5570e08c48b3562f74d33fc05c4"}, - {file = "pymongo-3.12.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfa217bf8cf3ff6b30c8e6a89014e0c0e7b50941af787b970060ae5ba04a4ce5"}, - {file = "pymongo-3.12.3-py2.7-macosx-10.14-intel.egg", hash = "sha256:d81299f63dc33cc172c26faf59cc54dd795fc6dd5821a7676cca112a5ee8bbd6"}, - {file = "pymongo-3.12.3.tar.gz", hash = "sha256:0a89cadc0062a5e53664dde043f6c097172b8c1c5f0094490095282ff9995a5f"}, + {file = "pymongo-3.13.0-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:3ad3a3df830f7df7e0856c2bdb54d19f5bf188bd7420985e18643b8e4d2a075f"}, + {file = "pymongo-3.13.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b96e0e9d2d48948240b510bac81614458fc10adcd3a93240c2fd96448b4efd35"}, + {file = "pymongo-3.13.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f592b202d77923498b32ddc5b376e5fa9ba280d3e16ed56cb8c932fe6d6a478"}, + {file = "pymongo-3.13.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:851f2bb52b5cb2f4711171ca925e0e05344a8452972a748a8a8ffdda1e1d72a7"}, + {file = "pymongo-3.13.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1c9d23f62a3fa7523d849c4942acc0d9ff7081ebc00c808ee7cfdc070df0687f"}, + {file = "pymongo-3.13.0-cp27-cp27m-win32.whl", hash = "sha256:a17b81f22398e3e0f72bdf938e98c810286994b2bcc0a125cd5ad8fd4ea54ad7"}, + {file = "pymongo-3.13.0-cp27-cp27m-win_amd64.whl", hash = "sha256:4f6dd55dab77adf60b445c11f426ee5cdfa1b86f6d54cb937bfcbf09572333ab"}, + {file = "pymongo-3.13.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:776f90bf2252f90a4ae838e7917638894c6356bef7265f424592e2fd1f577d05"}, + {file = "pymongo-3.13.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:50b99f4d3eee6f03778fe841d6f470e6c18e744dc665156da6da3bc6e65b398d"}, + {file = "pymongo-3.13.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50a81b2d9f188c7909e0a1084fa969bb92a788076809c437ac1ae80393f46df9"}, + {file = "pymongo-3.13.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c7c45a8a1a752002b0a7c81ab3a4c5e3b6f67f9826b16fbe3943f5329f565f24"}, + {file = "pymongo-3.13.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1037097708498bdc85f23c8798a5c46c7bce432d77d23608ff14e0d831f1a971"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux1_i686.whl", hash = "sha256:b5b733694e7df22d5c049581acfc487695a6ff813322318bed8dd66f79978636"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d7c91747ec8dde51440dd594603158cc98abb3f7df84b2ed8a836f138285e4fb"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:f4175fcdddf764d371ee52ec4505a40facee2533e84abf2953cda86d050cfa1f"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:93d4e9a02c17813b34e4bd9f6fbf07310c140c8f74341537c24d07c1cdeb24d1"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:3b261d593f2563299062733ae003a925420a86ff4ddda68a69097d67204e43f3"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:172db03182a22e9002157b262c1ea3b0045c73d4ff465adc152ce5b4b0e7b8d4"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09de3bfc995ae8cb955abb0c9ae963c134dba1b5622be3bcc527b89b0fd4091c"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0379447587ee4b8f983ba183202496e86c0358f47c45612619d634d1fcd82bd"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30245a8747dc90019a3c9ad9df987e0280a3ea632ad36227cde7d1d8dcba0830"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b6fddf6a7b91da044f202771a38e71bbb9bf42720a406b26b25fe2256e7102"}, + {file = "pymongo-3.13.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5831a377d15a626fbec10890ffebc4c6abcd37e4126737932cd780a171eabdc1"}, + {file = "pymongo-3.13.0-cp310-cp310-win32.whl", hash = "sha256:944249aa83dee314420c37d0f40c30a8f6dc4a3877566017b87062e53af449f4"}, + {file = "pymongo-3.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea8824ebc9a1a5c8269e8f1e3989b5a6bec876726e2f3c33ebd036cb488277f0"}, + {file = "pymongo-3.13.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bdd34c57b4da51a7961beb33645646d197e41f8517801dc76b37c1441e7a4e10"}, + {file = "pymongo-3.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f9cc42a162faa241c82e117ac85734ae9f14343dc2df1c90c6b2181f791b22"}, + {file = "pymongo-3.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a82a1c10f5608e6494913faa169e213d703194bfca0aa710901f303be212414"}, + {file = "pymongo-3.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8927f22ef6a16229da7f18944deac8605bdc2c0858be5184259f2f7ce7fd4459"}, + {file = "pymongo-3.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6f8191a282ef77e526f8f8f63753a437e4aa4bc78f5edd8b6b6ed0eaebd5363"}, + {file = "pymongo-3.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d9ed67c987bf9ac2ac684590ba3d2599cdfb0f331ee3db607f9684469b3b59d"}, + {file = "pymongo-3.13.0-cp311-cp311-win32.whl", hash = "sha256:e8f6979664ff477cd61b06bf8aba206df7b2334209815ab3b1019931dab643d6"}, + {file = "pymongo-3.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:174fd1000e896d0dfbc7f6d7e6a1992a4868796c7dec31679e38218c78d6a942"}, + {file = "pymongo-3.13.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:d1ee773fb72ba024e7e3bb6ea8907fe52bccafcb5184aaced6bad995bd30ea20"}, + {file = "pymongo-3.13.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:28565e3dbd69fe5fe35a210067064dbb6ed5abe997079f653c19c873c3896fe6"}, + {file = "pymongo-3.13.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5c1db7d366004d6c699eb08c716a63ae0a3e946d061cbebea65d7ce361950265"}, + {file = "pymongo-3.13.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e1956f3338c10308e2f99c2c9ff46ae412035cbcd7aaa76c39ccdb806854a247"}, + {file = "pymongo-3.13.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:10f0fddc1d63ba3d4a4bffcc7720184c1b7efd570726ad5e2f55818da320239f"}, + {file = "pymongo-3.13.0-cp35-cp35m-win32.whl", hash = "sha256:570ae3365b23d4fd8c669cb57613b1a90b2757e993588d3370ef90945dbeec4b"}, + {file = "pymongo-3.13.0-cp35-cp35m-win_amd64.whl", hash = "sha256:79f777eaf3f5b2c6d81f9ef00d87837001d7063302503bbcbfdbf3e9bc27c96f"}, + {file = "pymongo-3.13.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:d42eb29ba314adfd9c11234b4b646f61b0448bf9b00f14db4b317e6e4b947e77"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:e5e87c0eb774561c546f979342a8ff36ebee153c60a0b6c6b03ba989ceb9538c"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0f2c5a5984599a88d087a15859860579b825098b473d8c843f1979a83d159f2e"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:59c98e86c5e861032b71e6e5b65f23e6afaacea6e82483b66f1191a5021a7b4f"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:70b67390e27e58876853efbb87e43c85252de2515e2887f7dd901b4fa3d21973"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:42ba8606492d76e6f9e4c7a458ed4bc712603be393259a52450345f0945da2cf"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:0e5536994cf2d8488c6fd9dea71df3c4dbb3e0d2ba5e695da06d9142a29a0969"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:fe8194f107f0fa3cabd14e9e809f174eca335993c1db72d1e74e0f496e7afe1f"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d593d50815771f517d3ac4367ff716e3f3c78edae51d98e1e25791459f8848ff"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5136ebe8da6a1604998a8eb96be55935aa5f7129c41cc7bddc400d48e8df43be"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a424bdedfd84454d2905a861e0d4bb947cc5bd024fdeb3600c1a97d2be0f4255"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5161167b3840e9c84c80f2534ea6a099f51749d5673b662a3dd248be17c3208"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644470442beaf969df99c4e00367a817eee05f0bba5d888f1ba6fe97b5e1c102"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2406df90b2335371706c59b7d79e9633b81ed2a7ecd48c1faf8584552bdf2d90"}, + {file = "pymongo-3.13.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:222591b828de10ac90064047b5d4916953f38c38b155009c4b8b5e0d33117c2b"}, + {file = "pymongo-3.13.0-cp36-cp36m-win32.whl", hash = "sha256:7cb987b199fa223ad78eebaa9fbc183d5a5944bfe568a9d6f617316ca1c1f32f"}, + {file = "pymongo-3.13.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6cbb73d9fc2282677e2b7a137d13da987bd0b13abd88ed27bba5534c226db06"}, + {file = "pymongo-3.13.0-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:b1223b826acbef07a7f5eb9bf37247b0b580119916dca9eae19d92b1290f5855"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:398fb86d374dc351a4abc2e24cd15e5e14b2127f6d90ce0df3fdf2adcc55ac1b"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:9c3d07ea19cd2856d9943dce37e75d69ecbb5baf93c3e4c82f73b6075c481292"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:2943d739715f265a2983ac43747595b6af3312d0a370614040959fd293763adf"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:c3b70ed82f20d18d22eafc9bda0ea656605071762f7d31f3c5afc35c59d3393b"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:7ec2bb598847569ae34292f580842d37619eea3e546005042f485e15710180d5"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:8cc37b437cba909bef06499dadd91a39c15c14225e8d8c7870020049f8a549fe"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:65a063970e15a4f338f14b820561cf6cdaf2839691ac0adb2474ddff9d0b8b0b"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02f0e1a75d3bc0e16c7e15daf9c56185642be055e425f3b34888fc6eb1b22401"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e74b9c2aca2734c7f49f00fe68d6830a30d26df60e2ace7fe40ccb92087b94"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24e954be35ad4537840f20bbc8d75320ae647d3cb4fab12cb8fcd2d55f408e76"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a149377d1ff766fd618500798d0d94637f66d0ae222bb6d28f41f3e15c626297"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61660710b054ae52c8fc10368e91d74719eb05554b631d7f8ca93d21d2bff2e6"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4bbc0d27dfef7689285e54f2e0a224f0c7cd9d5c46d2638fabad5500b951c92f"}, + {file = "pymongo-3.13.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9b2ed9c3b30f11cd4a3fbfc22167af7987b01b444215c2463265153fe7cf66d6"}, + {file = "pymongo-3.13.0-cp37-cp37m-win32.whl", hash = "sha256:1c2c5e2b00e2fadcd590c0b2e293d71215e98ed1cb635cfca2be4998d197e534"}, + {file = "pymongo-3.13.0-cp37-cp37m-win_amd64.whl", hash = "sha256:32eac95bbb030b2376ffd897376c6f870222a3457f01a9ce466b9057876132f8"}, + {file = "pymongo-3.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a796ef39dadf9d73af05d24937644d386495e43a7d13617aa3651d836da542c8"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b6793baf4639c72a500698a49e9250b293e17ae1faf11ac1699d8141194786fe"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:80d8576b04d0824f63bf803190359c0d3bcb6e7fa63fefbd4bc0ceaa7faae38c"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:db2e11507fe9cc2a722be21ccc62c1b1295398fe9724c1f14900cdc7166fc0d7"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:b01ce58eec5edeededf1992d2dce63fb8565e437be12d6f139d75b15614c4d08"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:d1a19d6c5098f1f4e11430cd74621699453cbc534dd7ade9167e582f50814b19"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:7219b1a726ced3bacecabef9bd114529bbb69477901373e800d7d0140baadc95"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:2dae3b353a10c3767e0aa1c1492f2af388f1012b08117695ab3fd1f219e5814e"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12721d926d43d33dd3318e58dce9b0250e8a9c6e1093fa8e09f4805193ff4b43"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6af0a4b17faf26779d5caee8542a4f2cba040cea27d3bffc476cbc6ccbd4c8ee"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09b9d0f5a445c7e0ddcc021b09835aa6556f0166afc498f57dfdd72cdf6f02ad"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db5b4f8ad8607a3d612da1d4c89a84e4cf5c88f98b46365820d9babe5884ba45"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34dbf5fecf653c152edb75a35a8b15dfdc4549473484ee768aeb12c97983cead"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:34cd48df7e1fc69222f296d8f69e3957eb7c6b5aa0709d3467184880ed7538c0"}, + {file = "pymongo-3.13.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c8f755ff1f4ab4ca790d1d6d3229006100b301475948021b6b2757822e0d6c97"}, + {file = "pymongo-3.13.0-cp38-cp38-win32.whl", hash = "sha256:b0746d0d4535f56bbaa63a8f6da362f330804d578e66e126b226eebe76c2bf00"}, + {file = "pymongo-3.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ad0515abb132f52ce9d8abd1a29681a1e65dba7b7fe13ea01e1a8db5715bf80"}, + {file = "pymongo-3.13.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3c5cb6c93c94df76a879bad4b89db0104b01806d17c2b803c1316ba50962b6d6"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2e0854170813238f0c3131050c67cb1fb1ade75c93bf6cd156c1bd9a16095528"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1410faa51ce835cc1234c99ec42e98ab4f3c6f50d92d86a2d4f6e11c97ee7a4e"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d7910135f5de1c5c3578e61d6f4b087715b15e365f11d4fa51a9cee92988b2bd"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:028175dd8d2979a889153a2308e8e500b3df7d9e3fd1c33ca7fdeadf61cc87a2"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:2bfc39276c0e6d07c95bd1088b5003f049e986e089509f7dbd68bb7a4b1e65ac"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:4092b660ec720d44d3ca81074280dc25c7a3718df1b6c0fe9fe36ac6ed2833e4"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:5bdeb71a610a7b801416268e500e716d0fe693fb10d809e17f0fb3dac5be5a34"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa3bca8e76f5c00ed2bb4325e0e383a547d71595926d5275d7c88175aaf7435e"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c7cab8155f430ca460a6fc7ae8a705b34f3e279a57adb5f900eb81943ec777c"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4a32f3dfcca4a4816373bdb6256c18c78974ebb3430e7da988516cd95b2bd6e4"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ed2788a6ec68743e2040ab1d16573d7d9f6e7333e45070ce9268cbc93d148c"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:21e61a536ffed84d10376c21c13a6ed1ebefb61989a844952547c229d6aeedf3"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0665412dce26b2318092a33bd2d2327d487c4490cfcde158d6946d39b1e28d78"}, + {file = "pymongo-3.13.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:64ed1a5ce5e5926727eb0f87c698c4d9a7a9f7b0953683a65e9ce2b7cc5f8e91"}, + {file = "pymongo-3.13.0-cp39-cp39-win32.whl", hash = "sha256:7593cb1214185a0c5b43b96effc51ce82ddc933298ee36db7dc2bd45d61b4adc"}, + {file = "pymongo-3.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:3cfc9bc1e8b5667bc1f3dbe46d2f85b3f24ff7533893bdc1203058012db2c046"}, + {file = "pymongo-3.13.0-py2.7-macosx-10.14-intel.egg", hash = "sha256:bc04c92d05c142889c26810a4842273deb42e66411273cab4ad09268fe69ba69"}, + {file = "pymongo-3.13.0.tar.gz", hash = "sha256:e22d6cf5802cd09b674c307cc9e03870b8c37c503ebec3d25b86f2ce8c535dc7"}, ] pynacl = [ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, @@ -2346,10 +2803,42 @@ pynput = [ {file = "pynput-1.7.6-py3.9.egg", hash = "sha256:264429fbe676e98e9050ad26a7017453bdd08768adb25cafb918347cf9f1eb4a"}, {file = "pynput-1.7.6.tar.gz", hash = "sha256:3a5726546da54116b687785d38b1db56997ce1d28e53e8d22fc656d8b92e533c"}, ] -pyobjc-core = [] -pyobjc-framework-applicationservices = [] -pyobjc-framework-cocoa = [] -pyobjc-framework-quartz = [] +pyobjc-core = [ + {file = "pyobjc-core-9.0.1.tar.gz", hash = "sha256:5ce1510bb0bdff527c597079a42b2e13a19b7592e76850be7960a2775b59c929"}, + {file = "pyobjc_core-9.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b614406d46175b1438a9596b664bf61952323116704d19bc1dea68052a0aad98"}, + {file = "pyobjc_core-9.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bd397e729f6271c694fb70df8f5d3d3c9b2f2b8ac02fbbdd1757ca96027b94bb"}, + {file = "pyobjc_core-9.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d919934eaa6d1cf1505ff447a5c2312be4c5651efcb694eb9f59e86f5bd25e6b"}, + {file = "pyobjc_core-9.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:67d67ca8b164f38ceacce28a18025845c3ec69613f3301935d4d2c4ceb22e3fd"}, + {file = "pyobjc_core-9.0.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:39d11d71f6161ac0bd93cffc8ea210bb0178b56d16a7408bf74283d6ecfa7430"}, + {file = "pyobjc_core-9.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25be1c4d530e473ed98b15063b8d6844f0733c98914de6f09fe1f7652b772bbc"}, +] +pyobjc-framework-applicationservices = [ + {file = "pyobjc-framework-ApplicationServices-9.0.1.tar.gz", hash = "sha256:e3a350781fdcab6c1da4343dfc54ae3c0523e59e61147432f61dcfb365752fde"}, + {file = "pyobjc_framework_ApplicationServices-9.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c4214febf3cc2e417ae15d45b6502e5c20f1097cd042b025760d019fe69b07b6"}, + {file = "pyobjc_framework_ApplicationServices-9.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c62693e01ba272fbadcd66677881311d2d63fda84b9662533fcc883c54be76d7"}, + {file = "pyobjc_framework_ApplicationServices-9.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6829df4dc4cf012bdc221d4e0296d6699b33ca89741569df153989a0c18aa40e"}, + {file = "pyobjc_framework_ApplicationServices-9.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5af5d12871499c429dd68c5ec4be56c631ec8439aa953c266eed9afdffb5ec2b"}, + {file = "pyobjc_framework_ApplicationServices-9.0.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:724da9dfae6ab0505b90340231a685720288caecfcca335b08903102e97a93dc"}, + {file = "pyobjc_framework_ApplicationServices-9.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8e1dbfc8f482c433ce642724d4bed0c527c7f2f2f8b9ba1ac3f778a68cf1538d"}, +] +pyobjc-framework-cocoa = [ + {file = "pyobjc-framework-Cocoa-9.0.1.tar.gz", hash = "sha256:a8b53b3426f94307a58e2f8214dc1094c19afa9dcb96f21be12f937d968b2df3"}, + {file = "pyobjc_framework_Cocoa-9.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f94b0f92a62b781e633e58f09bcaded63d612f9b1e15202f5f372ea59e4aebd"}, + {file = "pyobjc_framework_Cocoa-9.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f062c3bb5cc89902e6d164aa9a66ffc03638645dd5f0468b6f525ac997c86e51"}, + {file = "pyobjc_framework_Cocoa-9.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0b374c0a9d32ba4fc5610ab2741cb05a005f1dfb82a47dbf2dbb2b3a34b73ce5"}, + {file = "pyobjc_framework_Cocoa-9.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8928080cebbce91ac139e460d3dfc94c7cb6935be032dcae9c0a51b247f9c2d9"}, + {file = "pyobjc_framework_Cocoa-9.0.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:9d2bd86a0a98d906f762f5dc59f2fc67cce32ae9633b02ff59ac8c8a33dd862d"}, + {file = "pyobjc_framework_Cocoa-9.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2a41053cbcee30e1e8914efa749c50b70bf782527d5938f2bc2a6393740969ce"}, +] +pyobjc-framework-quartz = [ + {file = "pyobjc-framework-Quartz-9.0.1.tar.gz", hash = "sha256:7e2e37fc5c01bbdc37c1355d886e6184d1977043d5a05d1d956573fa8503dac3"}, + {file = "pyobjc_framework_Quartz-9.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:13a546a2af7c1c5c2bbf88cce6891896a449e92466415ad14d9a5ee93fba6ef3"}, + {file = "pyobjc_framework_Quartz-9.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:93ee6e339ab6928115a92188a0162ec80bf62cd0bd908d54695c1b9f9381ea45"}, + {file = "pyobjc_framework_Quartz-9.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:066ffbe26de1456f79a6d9467dabd6a3b9ef228318a0ba3f3fedbdbc0e2d3444"}, + {file = "pyobjc_framework_Quartz-9.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9b553be6ef672e0886b0d2c77d1841b1a942c7b1dc9a67f6e1376dc5493513"}, + {file = "pyobjc_framework_Quartz-9.0.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7b39f85d0b747b0a13a11d0d538001b757c82d05e656eab437167b5b118307df"}, + {file = "pyobjc_framework_Quartz-9.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0bedb6e1b7789d5b24fd5c790f0d53e4c62930313c97a891068bfa0e966ccc0b"}, +] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, @@ -2362,8 +2851,8 @@ pytest = [ {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] pytest-cov = [ - {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, - {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, ] pytest-print = [ {file = "pytest_print-0.3.1-py2.py3-none-any.whl", hash = "sha256:3be6c66e4b23e53b489edfdf16857da9adf2c309dcc7c6fea01ae2ce3c7542ed"}, @@ -2376,13 +2865,16 @@ python-dateutil = [ python-engineio = [] python-socketio = [] python-xlib = [ - {file = "python-xlib-0.31.tar.gz", hash = "sha256:74d83a081f532bc07f6d7afcd6416ec38403d68f68b9b9dc9e1f28fbf2d799e9"}, - {file = "python_xlib-0.31-py2.py3-none-any.whl", hash = "sha256:1ec6ce0de73d9e6592ead666779a5732b384e5b8fb1f1886bd0a81cafa477759"}, + {file = "python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32"}, + {file = "python_xlib-0.33-py2.py3-none-any.whl", hash = "sha256:c3534038d42e0df2f1392a1b30a15a4ff5fdc2b86cfa94f072bf11b10a164398"}, ] python3-xlib = [ {file = "python3-xlib-0.15.tar.gz", hash = "sha256:dc4245f3ae4aa5949c1d112ee4723901ade37a96721ba9645f2bfa56e5b383f8"}, ] -pytz = [] +pytz = [ + {file = "pytz-2022.7-py2.py3-none-any.whl", hash = "sha256:93007def75ae22f7cd991c84e02d434876818661f8df9ad5df9e950ff4e52cfd"}, + {file = "pytz-2022.7.tar.gz", hash = "sha256:7ccfae7b4b2c067464a6733c6261673fdb8fd1be905460396b97a073e9fa683a"}, +] pywin32 = [ {file = "pywin32-301-cp35-cp35m-win32.whl", hash = "sha256:93367c96e3a76dfe5003d8291ae16454ca7d84bb24d721e0b74a07610b7be4a7"}, {file = "pywin32-301-cp35-cp35m-win_amd64.whl", hash = "sha256:9635df6998a70282bd36e7ac2a5cef9ead1627b0a63b17c731312c7a0daebb72"}, @@ -2399,6 +2891,41 @@ pywin32-ctypes = [ {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, ] +pyyaml = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] "qt.py" = [] qtawesome = [ {file = "QtAwesome-0.7.3-py2.py3-none-any.whl", hash = "sha256:ddf4530b4af71cec13b24b88a4cdb56ec85b1e44c43c42d0698804c7137b09b0"}, @@ -2414,7 +2941,10 @@ recommonmark = [ ] requests = [] rsa = [] -secretstorage = [] +secretstorage = [ + {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, + {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, +] semver = [ {file = "semver-2.13.0-py2.py3-none-any.whl", hash = "sha256:ced8b23dceb22134307c1b8abfa523da14198793d9787ac838e70e29e77458d4"}, {file = "semver-2.13.0.tar.gz", hash = "sha256:fa0fe2722ee1c3f57eac478820c3a5ae2f624af8264cbdf9000c980ff7f75e3f"}, @@ -2424,7 +2954,10 @@ six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -slack-sdk = [] +slack-sdk = [ + {file = "slack_sdk-3.19.5-py2.py3-none-any.whl", hash = "sha256:0b52bb32a87c71f638b9eb47e228dffeebf89de5e762684ef848276f9f186c84"}, + {file = "slack_sdk-3.19.5.tar.gz", hash = "sha256:47fb4af596243fe6585a92f3034de21eb2104a55cc9fd59a92ef3af17cf9ddd8"}, +] smmap = [ {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, @@ -2435,10 +2968,13 @@ snowballstemmer = [ ] speedcopy = [] sphinx = [] -sphinx-qt-documentation = [] +sphinx-qt-documentation = [ + {file = "sphinx_qt_documentation-0.4.1-py3-none-any.whl", hash = "sha256:5f756640507ba3ed00020ad23b39ee0e74f10d4518366d727995ef2f59b88894"}, + {file = "sphinx_qt_documentation-0.4.1.tar.gz", hash = "sha256:2ff1f2dcdead60b186d900220aa3ea1439827cc6319dd119ac2fff9f5eeff4b6"}, +] sphinx-rtd-theme = [ - {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, - {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"}, + {file = "sphinx_rtd_theme-1.1.1-py2.py3-none-any.whl", hash = "sha256:31faa07d3e97c8955637fc3f1423a5ab2c44b74b8cc558a51498c202ce5cbda7"}, + {file = "sphinx_rtd_theme-1.1.1.tar.gz", hash = "sha256:6146c845f1e1947b3c3dd4432c28998a1693ccc742b4f9ad7c63129f0757c103"}, ] sphinxcontrib-applehelp = [ {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, @@ -2485,12 +3021,22 @@ tomli = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] typed-ast = [] -typing-extensions = [] +typing-extensions = [ + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, +] uritemplate = [ {file = "uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"}, {file = "uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"}, ] -urllib3 = [] +urllib3 = [ + {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, + {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, +] +virtualenv = [ + {file = "virtualenv-20.17.1-py3-none-any.whl", hash = "sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4"}, + {file = "virtualenv-20.17.1.tar.gz", hash = "sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058"}, +] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, @@ -2504,5 +3050,83 @@ wsrpc-aiohttp = [ {file = "wsrpc-aiohttp-3.2.0.tar.gz", hash = "sha256:f467abc51bcdc760fc5aeb7041abdeef46eeca3928dc43dd6e7fa7a533563818"}, {file = "wsrpc_aiohttp-3.2.0-py3-none-any.whl", hash = "sha256:fa9b0bf5cb056898cb5c9f64cbc5eacb8a5dd18ab1b7f0cd4a2208b4a7fde282"}, ] -yarl = [] -zipp = [] +yarl = [ + {file = "yarl-1.8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bb81f753c815f6b8e2ddd2eef3c855cf7da193b82396ac013c661aaa6cc6b0a5"}, + {file = "yarl-1.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:47d49ac96156f0928f002e2424299b2c91d9db73e08c4cd6742923a086f1c863"}, + {file = "yarl-1.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3fc056e35fa6fba63248d93ff6e672c096f95f7836938241ebc8260e062832fe"}, + {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58a3c13d1c3005dbbac5c9f0d3210b60220a65a999b1833aa46bd6677c69b08e"}, + {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10b08293cda921157f1e7c2790999d903b3fd28cd5c208cf8826b3b508026996"}, + {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de986979bbd87272fe557e0a8fcb66fd40ae2ddfe28a8b1ce4eae22681728fef"}, + {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c4fcfa71e2c6a3cb568cf81aadc12768b9995323186a10827beccf5fa23d4f8"}, + {file = "yarl-1.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae4d7ff1049f36accde9e1ef7301912a751e5bae0a9d142459646114c70ecba6"}, + {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf071f797aec5b96abfc735ab97da9fd8f8768b43ce2abd85356a3127909d146"}, + {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:74dece2bfc60f0f70907c34b857ee98f2c6dd0f75185db133770cd67300d505f"}, + {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:df60a94d332158b444301c7f569659c926168e4d4aad2cfbf4bce0e8fb8be826"}, + {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:63243b21c6e28ec2375f932a10ce7eda65139b5b854c0f6b82ed945ba526bff3"}, + {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cfa2bbca929aa742b5084fd4663dd4b87c191c844326fcb21c3afd2d11497f80"}, + {file = "yarl-1.8.2-cp310-cp310-win32.whl", hash = "sha256:b05df9ea7496df11b710081bd90ecc3a3db6adb4fee36f6a411e7bc91a18aa42"}, + {file = "yarl-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:24ad1d10c9db1953291f56b5fe76203977f1ed05f82d09ec97acb623a7976574"}, + {file = "yarl-1.8.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a1fca9588f360036242f379bfea2b8b44cae2721859b1c56d033adfd5893634"}, + {file = "yarl-1.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f37db05c6051eff17bc832914fe46869f8849de5b92dc4a3466cd63095d23dfd"}, + {file = "yarl-1.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77e913b846a6b9c5f767b14dc1e759e5aff05502fe73079f6f4176359d832581"}, + {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0978f29222e649c351b173da2b9b4665ad1feb8d1daa9d971eb90df08702668a"}, + {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388a45dc77198b2460eac0aca1efd6a7c09e976ee768b0d5109173e521a19daf"}, + {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2305517e332a862ef75be8fad3606ea10108662bc6fe08509d5ca99503ac2aee"}, + {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42430ff511571940d51e75cf42f1e4dbdded477e71c1b7a17f4da76c1da8ea76"}, + {file = "yarl-1.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3150078118f62371375e1e69b13b48288e44f6691c1069340081c3fd12c94d5b"}, + {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c15163b6125db87c8f53c98baa5e785782078fbd2dbeaa04c6141935eb6dab7a"}, + {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4d04acba75c72e6eb90745447d69f84e6c9056390f7a9724605ca9c56b4afcc6"}, + {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e7fd20d6576c10306dea2d6a5765f46f0ac5d6f53436217913e952d19237efc4"}, + {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:75c16b2a900b3536dfc7014905a128a2bea8fb01f9ee26d2d7d8db0a08e7cb2c"}, + {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6d88056a04860a98341a0cf53e950e3ac9f4e51d1b6f61a53b0609df342cc8b2"}, + {file = "yarl-1.8.2-cp311-cp311-win32.whl", hash = "sha256:fb742dcdd5eec9f26b61224c23baea46c9055cf16f62475e11b9b15dfd5c117b"}, + {file = "yarl-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:8c46d3d89902c393a1d1e243ac847e0442d0196bbd81aecc94fcebbc2fd5857c"}, + {file = "yarl-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ceff9722e0df2e0a9e8a79c610842004fa54e5b309fe6d218e47cd52f791d7ef"}, + {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f6b4aca43b602ba0f1459de647af954769919c4714706be36af670a5f44c9c1"}, + {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1684a9bd9077e922300ecd48003ddae7a7474e0412bea38d4631443a91d61077"}, + {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebb78745273e51b9832ef90c0898501006670d6e059f2cdb0e999494eb1450c2"}, + {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3adeef150d528ded2a8e734ebf9ae2e658f4c49bf413f5f157a470e17a4a2e89"}, + {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57a7c87927a468e5a1dc60c17caf9597161d66457a34273ab1760219953f7f4c"}, + {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:efff27bd8cbe1f9bd127e7894942ccc20c857aa8b5a0327874f30201e5ce83d0"}, + {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a783cd344113cb88c5ff7ca32f1f16532a6f2142185147822187913eb989f739"}, + {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:705227dccbe96ab02c7cb2c43e1228e2826e7ead880bb19ec94ef279e9555b5b"}, + {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:34c09b43bd538bf6c4b891ecce94b6fa4f1f10663a8d4ca589a079a5018f6ed7"}, + {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a48f4f7fea9a51098b02209d90297ac324241bf37ff6be6d2b0149ab2bd51b37"}, + {file = "yarl-1.8.2-cp37-cp37m-win32.whl", hash = "sha256:0414fd91ce0b763d4eadb4456795b307a71524dbacd015c657bb2a39db2eab89"}, + {file = "yarl-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:d881d152ae0007809c2c02e22aa534e702f12071e6b285e90945aa3c376463c5"}, + {file = "yarl-1.8.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5df5e3d04101c1e5c3b1d69710b0574171cc02fddc4b23d1b2813e75f35a30b1"}, + {file = "yarl-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7a66c506ec67eb3159eea5096acd05f5e788ceec7b96087d30c7d2865a243918"}, + {file = "yarl-1.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2b4fa2606adf392051d990c3b3877d768771adc3faf2e117b9de7eb977741229"}, + {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e21fb44e1eff06dd6ef971d4bdc611807d6bd3691223d9c01a18cec3677939e"}, + {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93202666046d9edadfe9f2e7bf5e0782ea0d497b6d63da322e541665d65a044e"}, + {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc77086ce244453e074e445104f0ecb27530d6fd3a46698e33f6c38951d5a0f1"}, + {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dd68a92cab699a233641f5929a40f02a4ede8c009068ca8aa1fe87b8c20ae3"}, + {file = "yarl-1.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b372aad2b5f81db66ee7ec085cbad72c4da660d994e8e590c997e9b01e44901"}, + {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e6f3515aafe0209dd17fb9bdd3b4e892963370b3de781f53e1746a521fb39fc0"}, + {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dfef7350ee369197106805e193d420b75467b6cceac646ea5ed3049fcc950a05"}, + {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:728be34f70a190566d20aa13dc1f01dc44b6aa74580e10a3fb159691bc76909d"}, + {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ff205b58dc2929191f68162633d5e10e8044398d7a45265f90a0f1d51f85f72c"}, + {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baf211dcad448a87a0d9047dc8282d7de59473ade7d7fdf22150b1d23859f946"}, + {file = "yarl-1.8.2-cp38-cp38-win32.whl", hash = "sha256:272b4f1599f1b621bf2aabe4e5b54f39a933971f4e7c9aa311d6d7dc06965165"}, + {file = "yarl-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:326dd1d3caf910cd26a26ccbfb84c03b608ba32499b5d6eeb09252c920bcbe4f"}, + {file = "yarl-1.8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f8ca8ad414c85bbc50f49c0a106f951613dfa5f948ab69c10ce9b128d368baf8"}, + {file = "yarl-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:418857f837347e8aaef682679f41e36c24250097f9e2f315d39bae3a99a34cbf"}, + {file = "yarl-1.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae0eec05ab49e91a78700761777f284c2df119376e391db42c38ab46fd662b77"}, + {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:009a028127e0a1755c38b03244c0bea9d5565630db9c4cf9572496e947137a87"}, + {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3edac5d74bb3209c418805bda77f973117836e1de7c000e9755e572c1f7850d0"}, + {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da65c3f263729e47351261351b8679c6429151ef9649bba08ef2528ff2c423b2"}, + {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef8fb25e52663a1c85d608f6dd72e19bd390e2ecaf29c17fb08f730226e3a08"}, + {file = "yarl-1.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcd7bb1e5c45274af9a1dd7494d3c52b2be5e6bd8d7e49c612705fd45420b12d"}, + {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44ceac0450e648de86da8e42674f9b7077d763ea80c8ceb9d1c3e41f0f0a9951"}, + {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:97209cc91189b48e7cfe777237c04af8e7cc51eb369004e061809bcdf4e55220"}, + {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:48dd18adcf98ea9cd721a25313aef49d70d413a999d7d89df44f469edfb38a06"}, + {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e59399dda559688461762800d7fb34d9e8a6a7444fd76ec33220a926c8be1516"}, + {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d617c241c8c3ad5c4e78a08429fa49e4b04bedfc507b34b4d8dceb83b4af3588"}, + {file = "yarl-1.8.2-cp39-cp39-win32.whl", hash = "sha256:cb6d48d80a41f68de41212f3dfd1a9d9898d7841c8f7ce6696cf2fd9cb57ef83"}, + {file = "yarl-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:6604711362f2dbf7160df21c416f81fac0de6dbcf0b5445a2ef25478ecc4c778"}, + {file = "yarl-1.8.2.tar.gz", hash = "sha256:49d43402c6e3013ad0978602bf6bf5328535c48d192304b91b97a3c6790b1562"}, +] +zipp = [ + {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"}, + {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"}, +] diff --git a/pyproject.toml b/pyproject.toml index f74f40c561..e3b878882d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,6 +94,7 @@ recommonmark = "*" wheel = "*" enlighten = "*" # cool terminal progress bars toml = "^0.10.2" # for parsing pyproject.toml +pre-commit = "*" [tool.poetry.urls] "Bug Tracker" = "https://github.com/pypeclub/openpype/issues" From 5c6d86e06b84c464d0bafb640d5ef428f3d60650 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 6 Jan 2023 10:35:14 +0100 Subject: [PATCH 194/211] maya: fix typo in template builder --- openpype/hosts/maya/api/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 1d3f1cf568..3416c98793 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -240,7 +240,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): cmds.setAttr(node + ".hiddenInOutliner", True) def load_succeed(self, placeholder, container): - self._parent_in_hierarhchy(placeholder, container) + self._parent_in_hierarchy(placeholder, container) def _parent_in_hierarchy(self, placeholder, container): """Parent loaded container to placeholder's parent. From 20b2b50bac741d82b454b207d83c1ca5bda849a3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 6 Jan 2023 10:35:54 +0100 Subject: [PATCH 195/211] global: adding project anatomy data for formating --- openpype/pipeline/workfile/workfile_template_builder.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index a834ca0e21..390a5759fc 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -691,7 +691,14 @@ class AbstractTemplateBuilder(object): key: value for key, value in os.environ.items() } + fill_data["root"] = anatomy.roots + fill_data["project"] = { + "name": project_name, + "code": anatomy["attributes"]["code"] + } + + result = StringTemplate.format_template(path, fill_data) if result.solved: path = result.normalized() From 673e7a735928408dcc7eae463aba62af2a53744a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Fri, 6 Jan 2023 10:38:36 +0100 Subject: [PATCH 196/211] Update openpype/pipeline/workfile/workfile_template_builder.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/pipeline/workfile/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 390a5759fc..58f152591f 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1517,7 +1517,7 @@ class PlaceholderCreateMixin(object): for creator_name, creator in creators_by_name.items() ] - creator_items = list(sorted(creator_items, key=lambda i: i[1])) + creator_items.sort(key=lambda i: i[1]) options = options or {} return [ attribute_definitions.UISeparatorDef(), From d6004c26462e3f0400674ce1fbc3b6936c46b5cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Fri, 6 Jan 2023 10:39:43 +0100 Subject: [PATCH 197/211] Update openpype/pipeline/workfile/workfile_template_builder.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/pipeline/workfile/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 58f152591f..4fa45cdf30 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1574,7 +1574,7 @@ class PlaceholderCreateMixin(object): creator_name = placeholder.data["creator"] create_variant = placeholder.data["create_variant"] - creator_plugin = get_legacy_creator_by_name(creator_name) + creator_plugin = self.builder.get_creators_by_name()[creator_name] # create subset name project_name = legacy_io.Session["AVALON_PROJECT"] From c071140a6fcc8525b78f7f6b3bce8303bc011505 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 6 Jan 2023 10:54:06 +0100 Subject: [PATCH 198/211] PR comments --- .../workfile/workfile_template_builder.py | 25 +++++++++++-------- .../schema_templated_workfile_build.json | 2 +- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 4fa45cdf30..e3821bb4d7 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -43,7 +43,6 @@ from openpype.pipeline.load import ( load_with_repre_context, ) from openpype.pipeline.create import ( - get_legacy_creator_by_name, discover_legacy_creator_plugins ) @@ -439,7 +438,7 @@ class AbstractTemplateBuilder(object): template_path = template_preset["path"] if keep_placeholders is None: - keep_placeholders = template_preset["placeholder_keep"] + keep_placeholders = template_preset["keep_placeholder"] self.import_template(template_path) self.populate_scene_placeholders( @@ -673,10 +672,10 @@ class AbstractTemplateBuilder(object): path = profile["path"] # switch to remove placeholders after they are used - placeholder_keep = profile.get("placeholder_keep") + keep_placeholder = profile.get("keep_placeholder") # backward compatibility, since default is True - if placeholder_keep is None: - placeholder_keep = True + if keep_placeholder is None: + keep_placeholder = True if not path: raise TemplateLoadFailed(( @@ -707,7 +706,7 @@ class AbstractTemplateBuilder(object): self.log.info("Found template at: '{}'".format(path)) return { "path": path, - "placeholder_keep": placeholder_keep + "keep_placeholder": keep_placeholder } solved_path = None @@ -736,7 +735,7 @@ class AbstractTemplateBuilder(object): return { "path": solved_path, - "placeholder_keep": placeholder_keep + "keep_placeholder": keep_placeholder } @@ -991,7 +990,7 @@ class PlaceholderItem(object): def __init__(self, scene_identifier, data, plugin): self._log = None - self.name = scene_identifier + self._scene_identifier = scene_identifier self._data = data self._plugin = plugin @@ -1056,7 +1055,13 @@ class PlaceholderItem(object): return self._log def __repr__(self): - return "< {} {} >".format(self.__class__.__name__, self.name) + name = None + if hasattr("name", self): + name = self.name + if hasattr("_scene_identifier ", self): + name = self._scene_identifier + + return "< {} {} >".format(self.__class__.__name__, name) @property def order(self): @@ -1069,7 +1074,7 @@ class PlaceholderItem(object): @property def scene_identifier(self): - return self.name + return self._scene_identifier @property def finished(self): diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json index 1826734291..b244460bbf 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json @@ -30,7 +30,7 @@ "multipath": false }, { - "key": "placeholder_keep", + "key": "keep_placeholder", "label": "Keep placeholders", "type": "boolean", "default": true From cd2324f07e48e03b36a99918d3110e6d505757f4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 6 Jan 2023 15:42:47 +0100 Subject: [PATCH 199/211] fix how host ip is received --- .../ftrack/ftrack_server/event_server_cli.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/ftrack_server/event_server_cli.py b/openpype/modules/ftrack/ftrack_server/event_server_cli.py index 20c5ab24a8..9adc784224 100644 --- a/openpype/modules/ftrack/ftrack_server/event_server_cli.py +++ b/openpype/modules/ftrack/ftrack_server/event_server_cli.py @@ -169,6 +169,22 @@ def legacy_server(ftrack_url): time.sleep(1) +def get_host_ip(): + host_name = socket.gethostname() + try: + return socket.gethostbyname(host_name) + except Exception: + pass + + try: + import ipaddress + return socket.gethostbyname(str(ipaddress.ip_address(8888))) + + except Exception: + pass + return None + + def main_loop(ftrack_url): """ This is main loop of event handling. @@ -245,11 +261,13 @@ def main_loop(ftrack_url): ) host_name = socket.gethostname() + host_ip = get_host_ip() + main_info = [ ["created_at", datetime.datetime.now().strftime("%Y.%m.%d %H:%M:%S")], ["Username", getpass.getuser()], ["Host Name", host_name], - ["Host IP", socket.gethostbyname(host_name)], + ["Host IP", host_ip or "N/A"], ["OpenPype executable", get_openpype_execute_args()[-1]], ["OpenPype version", get_openpype_version() or "N/A"], ["OpenPype build version", get_build_version() or "N/A"] From bf65fd495d3da90fc525e285cd1eef6511a7f486 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 6 Jan 2023 17:19:02 +0100 Subject: [PATCH 200/211] :art: add pre-commit installation to create_env scripts --- .pre-commit-config.yaml | 16 ++++++++++++++++ tools/create_env.ps1 | 8 ++++++++ tools/create_env.sh | 4 +++- 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..40159f4344 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: no-commit-to-branch + args: [ '--pattern', '^(?!((enhancement|feature|bugfix|documentation|tests)\/[a-zA-Z0-9\-]+)$).*' ] +- repo: https://github.com/psf/black + rev: 22.12.0 + hooks: + - id: black diff --git a/tools/create_env.ps1 b/tools/create_env.ps1 index 75cba3f65e..5e088df075 100644 --- a/tools/create_env.ps1 +++ b/tools/create_env.ps1 @@ -179,6 +179,14 @@ if ($LASTEXITCODE -ne 0) { Set-Location -Path $current_dir Exit-WithCode 1 } +Write-Color -Text ">>> ", "Installing pre-commit hooks ..." -Color Green, White +& "$env:POETRY_HOME\bin\poetry" run pre-commit install +if ($LASTEXITCODE -ne 0) { + Write-Color -Text "!!! ", "Installation of pre-commit hooks failed." -Color Red, Yellow + Set-Location -Path $current_dir + Exit-WithCode 1 +} + $endTime = [int][double]::Parse((Get-Date -UFormat %s)) Set-Location -Path $current_dir try diff --git a/tools/create_env.sh b/tools/create_env.sh index 1ecd960fe1..f2a33fdd3c 100755 --- a/tools/create_env.sh +++ b/tools/create_env.sh @@ -191,10 +191,12 @@ main () { # reinstalling them solves the problem. echo -e "${BIGreen}>>>${RST} Post-venv creation fixes ..." local openpype_index=$("$POETRY_HOME/bin/poetry" run python "$openpype_root/tools/parse_pyproject.py" tool.poetry.source.0.url) - echo -e "${BIGreen}- ${RST} Using index: ${BIWhite}$openpype_index${RST}" + echo -e "${BIGreen}- ${RST} Using index: ${BIWhite}$openpype_index${RST}" "$POETRY_HOME/bin/poetry" run pip install setuptools==49.6.0 "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall wheel "$POETRY_HOME/bin/poetry" run python -m pip install --disable-pip-version-check --force-reinstall pip + echo -e "${BIGreen}>>>${RST} Installing pre-commit hooks ..." + "$POETRY_HOME/bin/poetry" run pre-commit install } return_code=0 From e8426294e2d5bccd836bfa442c6560f2ee032818 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 6 Jan 2023 17:38:47 +0100 Subject: [PATCH 201/211] :art: fix version and add local branch prefix --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 40159f4344..1262f5e67d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,14 +2,14 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files - id: no-commit-to-branch - args: [ '--pattern', '^(?!((enhancement|feature|bugfix|documentation|tests)\/[a-zA-Z0-9\-]+)$).*' ] + args: [ '--pattern', '^(?!((enhancement|feature|bugfix|documentation|tests|local)\/[a-zA-Z0-9\-]+)$).*' ] - repo: https://github.com/psf/black rev: 22.12.0 hooks: From e1edb76f731097f9887c096db0fdcb05aaed0616 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 6 Jan 2023 17:48:05 +0100 Subject: [PATCH 202/211] use 'get_host_ip' on more places --- .../action_where_run_ask.py | 4 ++-- .../ftrack/ftrack_server/event_server_cli.py | 17 +---------------- openpype/modules/ftrack/ftrack_server/lib.py | 19 ++++++++++++++++++- .../ftrack/scripts/sub_event_status.py | 7 ++++--- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_where_run_ask.py b/openpype/modules/ftrack/event_handlers_user/action_where_run_ask.py index 0d69913996..65d1b42d82 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_where_run_ask.py +++ b/openpype/modules/ftrack/event_handlers_user/action_where_run_ask.py @@ -3,6 +3,7 @@ import socket import getpass from openpype_modules.ftrack.lib import BaseAction +from openpype_modules.ftrack.ftrack_server.lib import get_host_ip class ActionWhereIRun(BaseAction): @@ -53,8 +54,7 @@ class ActionWhereIRun(BaseAction): try: host_name = socket.gethostname() msgs["Hostname"] = host_name - host_ip = socket.gethostbyname(host_name) - msgs["IP"] = host_ip + msgs["IP"] = get_host_ip() or "N/A" except Exception: pass diff --git a/openpype/modules/ftrack/ftrack_server/event_server_cli.py b/openpype/modules/ftrack/ftrack_server/event_server_cli.py index 9adc784224..25ebad6658 100644 --- a/openpype/modules/ftrack/ftrack_server/event_server_cli.py +++ b/openpype/modules/ftrack/ftrack_server/event_server_cli.py @@ -26,6 +26,7 @@ from openpype_modules.ftrack import ( ) from openpype_modules.ftrack.lib import credentials from openpype_modules.ftrack.ftrack_server import socket_thread +from openpype_modules.ftrack.ftrack_server.lib import get_host_ip class MongoPermissionsError(Exception): @@ -169,22 +170,6 @@ def legacy_server(ftrack_url): time.sleep(1) -def get_host_ip(): - host_name = socket.gethostname() - try: - return socket.gethostbyname(host_name) - except Exception: - pass - - try: - import ipaddress - return socket.gethostbyname(str(ipaddress.ip_address(8888))) - - except Exception: - pass - return None - - def main_loop(ftrack_url): """ This is main loop of event handling. diff --git a/openpype/modules/ftrack/ftrack_server/lib.py b/openpype/modules/ftrack/ftrack_server/lib.py index c8143f739c..61d3bfa259 100644 --- a/openpype/modules/ftrack/ftrack_server/lib.py +++ b/openpype/modules/ftrack/ftrack_server/lib.py @@ -9,8 +9,9 @@ import time import queue import collections import appdirs -import pymongo +import socket +import pymongo import requests import ftrack_api import ftrack_api.session @@ -32,6 +33,22 @@ TOPIC_STATUS_SERVER = "openpype.event.server.status" TOPIC_STATUS_SERVER_RESULT = "openpype.event.server.status.result" +def get_host_ip(): + host_name = socket.gethostname() + try: + return socket.gethostbyname(host_name) + except Exception: + pass + + try: + import ipaddress + return socket.gethostbyname(str(ipaddress.ip_address(8888))) + + except Exception: + pass + return None + + class SocketBaseEventHub(ftrack_api.event.hub.EventHub): hearbeat_msg = b"hearbeat" diff --git a/openpype/modules/ftrack/scripts/sub_event_status.py b/openpype/modules/ftrack/scripts/sub_event_status.py index eb3f63c04b..dc5836e7f2 100644 --- a/openpype/modules/ftrack/scripts/sub_event_status.py +++ b/openpype/modules/ftrack/scripts/sub_event_status.py @@ -15,7 +15,8 @@ from openpype_modules.ftrack.ftrack_server.lib import ( SocketSession, StatusEventHub, TOPIC_STATUS_SERVER, - TOPIC_STATUS_SERVER_RESULT + TOPIC_STATUS_SERVER_RESULT, + get_host_ip ) from openpype.lib import ( Logger, @@ -29,10 +30,10 @@ log = Logger.get_logger("Event storer") action_identifier = ( "event.server.status" + os.environ["FTRACK_EVENT_SUB_ID"] ) -host_ip = socket.gethostbyname(socket.gethostname()) +host_ip = get_host_ip() action_data = { "label": "OpenPype Admin", - "variant": "- Event server Status ({})".format(host_ip), + "variant": "- Event server Status ({})".format(host_ip or "IP N/A"), "description": "Get Infromation about event server", "actionIdentifier": action_identifier } From 1c530c0cb4c35353b7b697905d79c5628c705ff3 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 6 Jan 2023 18:09:17 +0100 Subject: [PATCH 203/211] skip ipaddress way to receive ip address --- openpype/modules/ftrack/ftrack_server/lib.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openpype/modules/ftrack/ftrack_server/lib.py b/openpype/modules/ftrack/ftrack_server/lib.py index 61d3bfa259..eb64063fab 100644 --- a/openpype/modules/ftrack/ftrack_server/lib.py +++ b/openpype/modules/ftrack/ftrack_server/lib.py @@ -40,12 +40,6 @@ def get_host_ip(): except Exception: pass - try: - import ipaddress - return socket.gethostbyname(str(ipaddress.ip_address(8888))) - - except Exception: - pass return None From 823f661c47d254e6560dd33945a942d0e92a55c0 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 7 Jan 2023 03:27:59 +0000 Subject: [PATCH 204/211] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index ae514e371e..732682dd60 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.6" +__version__ = "3.14.10-nightly.7" From 4cc66395c5a60c82cd862165c849591a112180f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Jan 2023 06:31:59 +0000 Subject: [PATCH 205/211] Bump json5 from 1.0.1 to 1.0.2 in /website Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- website/yarn.lock | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/website/yarn.lock b/website/yarn.lock index 220a489dfa..9af21c7500 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -4740,9 +4740,9 @@ json-schema-traverse@^1.0.0: integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" @@ -5154,16 +5154,11 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0: +minimist@^1.2.0, minimist@^1.2.5: version "1.2.7" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== -minimist@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" From c39919a2d472b19dd07ab2596594dc92b5f9d2d7 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 10 Jan 2023 15:43:39 +0100 Subject: [PATCH 206/211] :art: add chore prefix --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1262f5e67d..7ba6276053 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: check-yaml - id: check-added-large-files - id: no-commit-to-branch - args: [ '--pattern', '^(?!((enhancement|feature|bugfix|documentation|tests|local)\/[a-zA-Z0-9\-]+)$).*' ] + args: [ '--pattern', '^(?!((enhancement|feature|bugfix|documentation|tests|local|chore)\/[a-zA-Z0-9\-]+)$).*' ] - repo: https://github.com/psf/black rev: 22.12.0 hooks: From c2d02e63300c9f5c03debbb4e2c314d45be40212 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 10 Jan 2023 16:56:48 +0100 Subject: [PATCH 207/211] add missing files used in harmony docs --- website/docs/artist_hosts_harmony.md | 14 +++++++------- website/docs/assets/harmony_publish.png | Bin 0 -> 19124 bytes .../docs/assets/harmony_publish_actions.png | Bin 0 -> 20614 bytes website/docs/assets/harmony_publish_expand.png | Bin 0 -> 35555 bytes .../docs/assets/harmony_publish_inspect.png | Bin 0 -> 21540 bytes website/docs/assets/harmony_publish_repair.gif | Bin 0 -> 959626 bytes 6 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 website/docs/assets/harmony_publish.png create mode 100644 website/docs/assets/harmony_publish_actions.png create mode 100644 website/docs/assets/harmony_publish_expand.png create mode 100644 website/docs/assets/harmony_publish_inspect.png create mode 100644 website/docs/assets/harmony_publish_repair.gif diff --git a/website/docs/artist_hosts_harmony.md b/website/docs/artist_hosts_harmony.md index 3e945a2852..bbd6ea4bec 100644 --- a/website/docs/artist_hosts_harmony.md +++ b/website/docs/artist_hosts_harmony.md @@ -62,7 +62,7 @@ When you `Use selection` on creation, the last selected node will be connected t `OpenPype > Publish` -![Publish](assets/photoshop_publish.PNG) +![Publish](assets/harmony_publish.png) This tool will run through checks to make sure the contents you are publishing is correct. Hit the "Play" button to start publishing. @@ -72,25 +72,25 @@ You may encounter issues with publishing which will be indicated with red square All validators will give some description about what the issue is. You can inspect this by going into the validator through the arrow: -![Inspect](assets/photoshop_publish_inspect.PNG) +![Inspect](assets/harmony_publish_inspect.png) You can expand the errors by clicking on them for more details: -![Expand](assets/photoshop_publish_expand.PNG) +![Expand](assets/harmony_publish_expand.png) Some validator have repair actions, which will fix the issue. If you can identify validators with actions by the circle icon with an "A": -![Actions](assets/photoshop_publish_actions.PNG) +![Actions](assets/harmony_publish_actions.png) To access the actions, you right click on the validator. If an action runs successfully, the actions icon will turn green. Once all issues are fixed, you can just hit the "Refresh" button and try to publish again. -![Repair](assets/photoshop_publish_repair.gif) +![Repair](assets/harmony_publish_repair.gif) ### Load `OpenPype > Load` -![Loader](assets/photoshop_loader.PNG) +![Loader](assets/photoshop_loader.png) The supported families for Harmony are: @@ -114,7 +114,7 @@ Loading templates or workfiles will import the contents into scene. Referencing `OpenPype > Manage` -![Loader](assets/photoshop_manage.PNG) +![Loader](assets/photoshop_manage.png) You can switch to a previous version of the image or update to the latest. diff --git a/website/docs/assets/harmony_publish.png b/website/docs/assets/harmony_publish.png new file mode 100644 index 0000000000000000000000000000000000000000..dc577571227a74706218549148ef0f59970adece GIT binary patch literal 19124 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ব*0>)r&{c$<7m9EKqFO_RN9aK6ET9@N;I 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/harmony_publish_expand.png b/website/docs/assets/harmony_publish_expand.png new file mode 100644 index 0000000000000000000000000000000000000000..6969b156476c4b165d3469dc1718df212cdd0158 GIT binary patch literal 35555 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 z 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 G{yzY@e;Nn? literal 0 HcmV?d00001 diff --git a/website/docs/assets/harmony_publish_inspect.png b/website/docs/assets/harmony_publish_inspect.png new file mode 100644 index 0000000000000000000000000000000000000000..d2fd8922af1fd71aa1090acd69a0cfecf8a4cfca GIT binary patch literal 21540 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

@4 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%0AmoI;R%IvGdyn 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Ðu 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

FPfVg-Pz_LZs|ze;0Nq9}xGkJH_ybj>FvK>1xw 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